WPF: уникальный стиль для каждого элемента поля со списком, привязанного к словарю

#wpf #xaml #binding #styles

#wpf #xaml #привязка #стили

Вопрос:

Поле со списком, привязанное к словарю (перечисления, строки). Выбранный путь к значению является ключом словаря.

Можно ли установить индивидуальный стиль для каждого элемента поля со списком в XAML?

Ответ №1:

Далее я использую вызываемое пользовательское перечисление Cards , содержащее константы Skull , Hearts и другие для демонстрационных целей. Вместо этого вы можете просто использовать свой тип перечисления.

Стиль контейнера элемента с использованием триггеров данных

Вы можете создать стиль контейнера items с триггерами для каждого значения enum.

 <Style x:Key="EnumComboBoxItemStyle"  TargetType="{x:Type ComboBoxItem}">
   <Style.Triggers>
      <DataTrigger Binding="{Binding Key}" Value="{x:Static local:Cards.Skull}">
         <Setter Property="Foreground" Value="Blue"/>
      </DataTrigger>
      <DataTrigger Binding="{Binding Key}" Value="{x:Static local:Cards.Hearts}">
         <Setter Property="Foreground" Value="Red"/>
      </DataTrigger>
   </Style.Triggers>
</Style>
  
 <ComboBox ItemContainerStyle="{StaticResource EnumComboBoxItemStyle}" ...>
  

Выбор стиля контейнера элемента

Другой вариант — создать селектор стилей, если у вас есть несколько разных стилей, подобных этому:

 <Style x:Key="SkullComboBoxItemStyle" TargetType="{x:Type ComboBoxItem}">
   <Setter Property="Foreground" Value="Green"/>
</Style>
<Style x:Key="HeartsComboBoxItemStyle" TargetType="{x:Type ComboBoxItem}">
   <Setter Property="Foreground" Value="Red"/>
</Style>
<!-- ...other styles. -->
  

Селектор стилей определяет стиль на основе значения enum .

 public class CardsKeyStyleSelector : StyleSelector
{
   public override Style SelectStyle(object item, DependencyObject container)
   {
      if (container is FrameworkElement element amp;amp; item is KeyValuePair<Cards, string> keyValuePair)
      {
         switch (keyValuePair.Key)
         {
            case Cards.Skull:
               return element.FindResource("SkullComboBoxItemStyle") as Style;
            case Cards.Hearts:
               return element.FindResource("HeartsComboBoxItemStyle") as Style;
            // ...other cases.
         }
      }

      return null;
   }
}
  

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

 <ComboBox ...>
   <ComboBox.ItemContainerStyleSelector>
      <local:CardsKeyStyleSelector/>
   </ComboBox.ItemContainerStyleSelector>
</ComboBox>
  

Комментарии:

1. Хорошо, спасибо! Я тоже нашел решение, используя ItemTemplate со стилем с триггерами. Не требуется никакого кода, кроме словаря и перечисления.

Ответ №2:

Мое решение заключается в следующем. Сначала определите перечислимый тип и словарь, связанный с ним:

 Public Enum MyEnum As Integer
    OneValue = 0
    OtherValue = 1
End Enum

Public ReadOnly Property MyDict As Dictionary(Of MyEnum, String)
    Get
        Return New Dictionary(Of MyEnum, String) From {
            {MyEnum.OneValue, "First value text"},
            {MyEnum.OtherValue, "Other value text"}
        }
    End Get
End Property
  

Далее, в XAML используйте его следующим образом:

 <Style TargetType="Ellipse" x:Key="ellipseStyle">
    <Setter Property="Height" Value="10" />
    <Setter Property="Width" Value="10" />
    <Style.Triggers>            
        <DataTrigger Binding="{Binding Key}" Value="0"><!-- "0" - one of the dictionary key -->
            <Setter Property="Fill" Value="Red" />
        </DataTrigger>          
        <DataTrigger Binding="{Binding Key}" Value="1"><!-- "1" - one of the dictionary key -->
            <Setter Property="Fill" Value="Green" />
        </DataTrigger>
    </Style.Triggers>
</Style>

<Style TargetType="{x:Type ComboBox}" x:Key="cmb_osn_rez">
    <Setter Property="ItemsSource" Value="{Binding MyDict}" />
    <Setter Property="SelectedValuePath" Value="Key" />
    <Setter Property="ItemsControl.ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Ellipse Style="{StaticResource ellipseStyle}" />
                    <TextBlock Text="{Binding Value}" />
                </StackPanel>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>