Содержимое тумблера не отображается в DataGrid

Я использую собственный стиль для моего тумблера. Стиль применяется, работает нормально и показывает ON или OFF. Проблема в том, что когда я добавляю тумблер в DataGrid.

Источник элемента DataGrid привязан к модели, а столбец isActive содержит элемент управления тумблером. Переключатель будет зеленого цвета, если isActive равен true, или красного цвета, если false, но не будет отображать текст содержимого ( ON , OFF ).

Стиль тумблера в файле ресурсов:

<Style x:Key="ActiveToggleSwitch" TargetType="{x:Type ToggleButton}">
    <Setter Property="IsChecked" Value="False"/>
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="VerticalAlignment" Value="Center" />
    <Setter Property="Template">

        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Grid x:Name="toggleSwitch">
                    <Border x:Name="Border" CornerRadius="10"
        Background="#C2283B"
        Width="90" Height="25">
                        <Border.Effect>
                            <DropShadowEffect ShadowDepth="0.6" Direction="0" Opacity="0.3" />
                        </Border.Effect>
                        <Ellipse x:Name="Ellipse" Fill="#FFFFFFFF" Stretch="Uniform"
             Margin="2 2 2 1"
             Stroke="Gray" StrokeThickness="0.2"
             HorizontalAlignment="Left" Width="22" >
                            <Ellipse.Effect>
                                <DropShadowEffect BlurRadius="10" ShadowDepth="1" Opacity="0.3" Direction="260" />
                            </Ellipse.Effect>
                        </Ellipse>
                    </Border>

                    <TextBlock x:Name="txtOff" Text="{Binding TextOFF}" Margin="0 0 40 0" VerticalAlignment="Center" FontWeight="DemiBold" HorizontalAlignment="Right" Foreground="White" FontSize="10" />
                    <TextBlock Opacity="0" x:Name="txtOn"  Text="{Binding TextON}" Margin="40 0 0 0" VerticalAlignment="Center" FontWeight="DemiBold"  Foreground="White" HorizontalAlignment="Left" FontSize="10" />
                </Grid>

                <ControlTemplate.Triggers>
                    <Trigger Property="ToggleButton.IsChecked" Value="True" >
                        <Trigger.EnterActions>

                            <BeginStoryboard>

                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetName="Border"
                                Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                To="#34A543"
                                Duration="0:0:0.1" />
                                    <ThicknessAnimation Storyboard.TargetName="Ellipse"
                                    Storyboard.TargetProperty="Margin"
                                    To="60 2 2 1"
                                    Duration="0:0:0.1" />
                                    <DoubleAnimation
                            Storyboard.TargetName="txtOff" 
                            Storyboard.TargetProperty="(TextBlock.Opacity)"
                            From="1.0" To="0.0" Duration="0:0:0:0.1"     />
                                    <DoubleAnimation
                            Storyboard.TargetName="txtOn" 
                            Storyboard.TargetProperty="(TextBlock.Opacity)"
                            From="0.0" To="1.0" Duration="0:0:0:0.1"  />
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                        <!--  some out fading  -->
                        <Trigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetName="Border"
                                Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                To="#C2283B"
                                Duration="0:0:0.1" />
                                    <ThicknessAnimation Storyboard.TargetName="Ellipse"
                                    Storyboard.TargetProperty="Margin"
                                    To="2 2 2 1"
                                    Duration="0:0:0.1" />
                                    <DoubleAnimation
                            Storyboard.TargetName="txtOff" 
                            Storyboard.TargetProperty="(TextBlock.Opacity)"
                            From="0" To="1.0" Duration="0:0:0:0.1"       />
                                    <DoubleAnimation
                            Storyboard.TargetName="txtOn" 
                            Storyboard.TargetProperty="(TextBlock.Opacity)"
                            From="1.0" To="0.0" Duration="0:0:0:0.1" />
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.ExitActions>
                        <Setter Property="Foreground" Value="{DynamicResource IdealForegroundColorBrush}" />
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="False">
                    </Trigger>

                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" Value="{DynamicResource GrayBrush7}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="VerticalContentAlignment" Value="Center" />
</Style>

MainWindow.xaml:

<telerik:GridViewDataColumn x:Name="Activetoogle" IsReadOnly="True"  HeaderCellStyle="{StaticResource CustomGridViewHeaderCellStyle}" Header="{StaticResource ActivityTriggerSwitch}" DataMemberBinding="{Binding isActive}" Width="*">
    <telerik:GridViewDataColumn.CellTemplate>
        <DataTemplate>
            <StackPanel  Height ="Auto" >
                <ToggleButton  x:Name="isActive"  VerticalAlignment="Center" IsEnabled="False"  Style="{StaticResource ActiveToggleSwitch}"
                 HorizontalAlignment="Right" Width="auto" FlowDirection="RightToLeft" IsChecked="{Binding empisActive}" Content="{Binding ToogleContent}"  />
            </StackPanel>
        </DataTemplate>
    </telerik:GridViewDataColumn.CellTemplate>
</telerik:GridViewDataColumn>

MainWindow.xaml.cs

public MainWindow(){
    InitializeComponent();
    TextOFF = (string)Application.Current.Resources["NotActive"];
    TextON = (string)Application.Current.Resources["IsActive"];
}
// ...

Я пытаюсь отобразить текст в колонке тумблера, как мне это сделать?

Примечание. Это работает, если тумблер не создан внутри шаблона данных.

Кнопка-переключатель должна содержать текст (ON или OFF).

DataGrid с переключателями.


person Community    schedule 21.01.2021    source источник


Ответы (2)


Вы можете использовать строковый ресурс непосредственно в xaml, использование ViewModel в вашем случае является ненужным шагом.

xmlns:stringResources="clr-namespace:YourApp.Properties"

<TextBlock x:Name="txtOff" Text="{x:Static stringResources:Resources.NotActive}" Margin="0 0 40 0" VerticalAlignment="Center" FontWeight="DemiBold" HorizontalAlignment="Right" Foreground="White" FontSize="10" />
person Lana    schedule 21.01.2021
comment
Не могли бы вы дать мне более подробную информацию? - person ; 22.01.2021
comment
@csharp_devloper31 Что именно непонятно? Если вы используете Resource в xaml, вам не нужно заботиться о том, какую ViewModel использовать для привязки. - person Lana; 22.01.2021
comment
Я проверил ваш код, и это не работает для меня, я использую файл с именем window для стилей (код для стиля тумблера находится внутри него) - person ; 22.01.2021

Свойства TextOFF и TextON определяются в вашем MainWindow, а не в контексте данных текущего элемента в столбце представления сетки. Поскольку ваши привязки жестко привязаны к текущему контексту данных, это не работает, свойства там не определены.

Грязный обходной путь

Вы можете изменить контекст данных, как показано ниже, что является действительно грязным обходным путем и я не рекомендую его. Он устанавливает контекст данных в MainWindow, поэтому ToggleButton работает и использует контекст данных StackPanel для привязки элементов.

<ToggleButton  x:Name="isActive"
               VerticalAlignment="Center"
               IsEnabled="False"
               Style="{StaticResource ActiveToggleSwitch}"
               HorizontalAlignment="Right"
               Width="auto"
               FlowDirection="RightToLeft"
               DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type YourProject:MainWindow}}}"
               IsChecked="{Binding DataContext.empisActive, RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}}"
               Content="{Binding DataContext.ToogleContent, RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}}" />

Решения со свойствами зависимостей

Не следует использовать привязку пути к свойству непосредственно в шаблоне элемента управления. Эта привязка всегда будет основываться на точных именах свойств TextOFF и TextON и текущем контексте данных, вместо этого используйте один из следующих параметров:

  • Создайте пользовательский элемент управления, производный от ToggleButton, и добавьте свойства зависимостей для текстов On и Off.
  • Создайте настраиваемые прикрепленные свойства для текстов On и Off.

В обоих случаях вы можете привязать тексты снаружи. Я предпочитаю первый вариант, потому что ваша кнопка переключения может иметь другие свойства, которые она может показывать, которые соответствуют ее особому поведению или внешнему виду.

public class SwitchButton : ToggleButton
{
   static SwitchButton()
   {
      DefaultStyleKeyProperty.OverrideMetadata(typeof(SwitchButton),
         new FrameworkPropertyMetadata(typeof(SwitchButton)));
   }

   public static readonly DependencyProperty OffTextProperty = DependencyProperty.Register(
      nameof(OffText), typeof(string), typeof(SwitchButton));

   public static readonly DependencyProperty OnTextProperty = DependencyProperty.Register(
      nameof(OnText), typeof(string), typeof(SwitchButton));

   public string OffText
   {
      get => (string)GetValue(OffTextProperty);
      set => SetValue(OffTextProperty, value);
   }

   public string OnText
   {
      get => (string)GetValue(OnTextProperty);
      set => SetValue(OnTextProperty, value);
   }
}

Теперь удалите x:Key из шаблона и измените типы на SwitchButton. Без ключа стиль будет неявным и будет применяться ко всем SwitchButton элементам управления в области действия автоматически. Также обратите внимание, что привязки теперь TemplateBinding, которые привязываются к свойствам зависимостей файла SwitchButton.

<Style TargetType="{x:Type YourProject:SwitchButton}">
   <Setter Property="IsChecked"
           Value="False" />
   <Setter Property="HorizontalAlignment"
           Value="Left" />
   <Setter Property="VerticalAlignment"
           Value="Center" />
   <Setter Property="Template">

      <Setter.Value>
         <ControlTemplate TargetType="{x:Type YourProject:SwitchButton}">
            <Grid x:Name="toggleSwitch">
               <Border x:Name="Border"
                       CornerRadius="10"
                       Background="#C2283B"
                       Width="90"
                       Height="25">
                  <Border.Effect>
                     <DropShadowEffect ShadowDepth="0.6"
                                       Direction="0"
                                       Opacity="0.3" />
                  </Border.Effect>
                  <Ellipse x:Name="Ellipse"
                           Fill="#FFFFFFFF"
                           Stretch="Uniform"
                           Margin="2 2 2 1"
                           Stroke="Gray"
                           StrokeThickness="0.2"
                           HorizontalAlignment="Left"
                           Width="22">
                     <Ellipse.Effect>
                        <DropShadowEffect BlurRadius="10"
                                          ShadowDepth="1"
                                          Opacity="0.3"
                                          Direction="260" />
                     </Ellipse.Effect>
                  </Ellipse>
               </Border>

               <TextBlock x:Name="txtOff"
                          Text="{TemplateBinding OffText}"
                          Margin="0 0 40 0"
                          VerticalAlignment="Center"
                          FontWeight="DemiBold"
                          HorizontalAlignment="Right"
                          Foreground="White"
                          FontSize="10" />
               <TextBlock Opacity="0"
                          x:Name="txtOn"
                          Text="{TemplateBinding OnText}"
                          Margin="40 0 0 0"
                          VerticalAlignment="Center"
                          FontWeight="DemiBold"
                          Foreground="White"
                          HorizontalAlignment="Left"
                          FontSize="10" />
            </Grid>

            <ControlTemplate.Triggers>
               <Trigger Property="ToggleButton.IsChecked"
                        Value="True">
                  <Trigger.EnterActions>

                     <BeginStoryboard>

                        <Storyboard>
                           <ColorAnimation Storyboard.TargetName="Border"
                                           Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                           To="#34A543"
                                           Duration="0:0:0.1" />
                           <ThicknessAnimation Storyboard.TargetName="Ellipse"
                                               Storyboard.TargetProperty="Margin"
                                               To="60 2 2 1"
                                               Duration="0:0:0.1" />
                           <DoubleAnimation Storyboard.TargetName="txtOff"
                                            Storyboard.TargetProperty="(TextBlock.Opacity)"
                                            From="1.0"
                                            To="0.0"
                                            Duration="0:0:0:0.1" />
                           <DoubleAnimation Storyboard.TargetName="txtOn"
                                            Storyboard.TargetProperty="(TextBlock.Opacity)"
                                            From="0.0"
                                            To="1.0"
                                            Duration="0:0:0:0.1" />
                        </Storyboard>
                     </BeginStoryboard>
                  </Trigger.EnterActions>
                  <!--  some out fading  -->
                  <Trigger.ExitActions>
                     <BeginStoryboard>
                        <Storyboard>
                           <ColorAnimation Storyboard.TargetName="Border"
                                           Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                           To="#C2283B"
                                           Duration="0:0:0.1" />
                           <ThicknessAnimation Storyboard.TargetName="Ellipse"
                                               Storyboard.TargetProperty="Margin"
                                               To="2 2 2 1"
                                               Duration="0:0:0.1" />
                           <DoubleAnimation Storyboard.TargetName="txtOff"
                                            Storyboard.TargetProperty="(TextBlock.Opacity)"
                                            From="0"
                                            To="1.0"
                                            Duration="0:0:0:0.1" />
                           <DoubleAnimation Storyboard.TargetName="txtOn"
                                            Storyboard.TargetProperty="(TextBlock.Opacity)"
                                            From="1.0"
                                            To="0.0"
                                            Duration="0:0:0:0.1" />
                        </Storyboard>
                     </BeginStoryboard>
                  </Trigger.ExitActions>
                  <Setter Property="Foreground"
                          Value="{DynamicResource IdealForegroundColorBrush}" />
               </Trigger>
               <Trigger Property="IsMouseOver"
                        Value="False">
               </Trigger>

               <Trigger Property="IsEnabled"
                        Value="False">
                  <Setter Property="Foreground"
                          Value="{DynamicResource GrayBrush7}" />
               </Trigger>
            </ControlTemplate.Triggers>
         </ControlTemplate>
      </Setter.Value>
   </Setter>
   <Setter Property="VerticalContentAlignment"
           Value="Center" />
</Style>

Это позволяет привязывать тексты Off и On извне. В вашем случае вам нужно будет использовать привязку RelativeSource для доступа к свойствам TextOFF и TextON в вашем MainWindow.

<YourProject:SwitchButton  x:Name="isActive"
                           VerticalAlignment="Center"
                           IsEnabled="False"
                           HorizontalAlignment="Right"
                           Width="auto"
                           FlowDirection="RightToLeft"
                           IsChecked="{Binding empisActive}"
                           Content="{Binding ToogleContent}"
                           OffText="{Binding TextOFF, RelativeSource={RelativeSource AncestorType={x:Type YourProject:MainWindow}}}"
                           OnText="{Binding TextON, RelativeSource={RelativeSource AncestorType={x:Type YourProject:MainWindow}}}"/>
person thatguy    schedule 21.01.2021
comment
Спасибо за этот ответ, но я действительно не знаком со свойством ViewModel и Dependency, поэтому я ищу простое решение. - person ; 22.01.2021
comment
@ csharp_devloper31 Поскольку ваши привязки жестко связаны, обходной путь, хотя я его не рекомендую, вероятно, настолько прост, насколько это возможно. - person thatguy; 22.01.2021
comment
Как вы сказали в ответе, вы написали два метода, которые я могу использовать, не могли бы вы разделить их, чтобы точно понять первый метод (я думаю, что первый фрагмент кода касается первого варианта или первого метода) ?? - person ; 22.01.2021
comment
Первый вариант у меня не работает, это не окно, это страница - person ; 22.01.2021
comment
@csharp_devloper31 Я разделил оба решения. В вашем вопросе у вас есть MainWindow, поэтому я предположил, что это должно быть окно. Если вы используете Page, используйте DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type Page}}}". - person thatguy; 22.01.2021
comment
Хорошо, спасибо, я посмотрю, - person ; 22.01.2021
comment
Извините, это не работает для меня :( - person ; 22.01.2021
comment
@csharp_devloper31 Я думаю, вам следует обновить свой вопрос, чтобы предоставить больше контекста, где определены TextOFF и TextON, а также где определена ваша сетка данных. В противном случае нет никакого способа узнать, почему это не работает. - person thatguy; 22.01.2021
comment
Я добавил полный стиль тумблера - person ; 22.01.2021
comment
@csharp_devloper31 Да, стиль, но не код MainWindow или разметка, которая показывает, как определяются свойства и где они фактически используются, и здесь, похоже, проблема в том, что структура отличается от того, что предполагает вопрос. - person thatguy; 22.01.2021
comment
Что именно вы имеете в виду, я разместил код С# (MainWindow.xaml.cs), в котором я установил содержимое TextON и TextOFF, а для xaml я разместил код столбца, который содержит шаблон данных переключателя кнопка - person ; 25.01.2021