Styling WPF ComboBox items

2019-01-27 13:57发布

问题:

I have a very simple WPF application which displays a ComboBox which binds to a list of classes which represent people. Each 'Person' object has a Name string field, and a Sex enum. I would like the ComboBox to display a drop-down of the various people's Name field, but for each line to be styled according to the Sex field, for example, blue for males, pink for females. Can anyone tell me what I am doing wrong?

Here is the XML:

<Window x:Class="ComboBoxColour.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Orientation="Vertical">
        <ComboBox ItemsSource="{Binding People}" Width="100" Height="20">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Name="somePerson" Text="{Binding Path=Name}">                        
                        <TextBlock.Triggers>
                            <DataTrigger Binding="{Binding Path=Sex}" Value="Male">
                                <DataTrigger.Setters>
                                    <Setter Property="Foreground" Value="Blue" TargetName="somePerson" />
                                </DataTrigger.Setters>
                            </DataTrigger>
                        </TextBlock.Triggers>                        
                    </TextBlock>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </StackPanel>
</Window>

And here is the C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

namespace ComboBoxColour
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
  {
    public List<Person> people;
    public List<Person> People
    {
      get { return people; }
      set { people = value; }
    }

    public MainWindow()
    {
      this.DataContext = this;

      People = new List<Person>();
      People.Add(new Person("Alice", SexEnum.Female));
      People.Add(new Person("Bob", SexEnum.Male));
      People.Add(new Person("Claire", SexEnum.Female));
      People.Add(new Person("Daniel", SexEnum.Male));

      InitializeComponent();
    }
  }

  public enum SexEnum{Male,Female};

  public class Person
  {
    private string name;
    public string Name
    {
      get { return name; }
      set { name = value; }
    }

    private SexEnum sex;
    public SexEnum Sex
    {
      get { return sex; }
      set { sex = value; }
    }

    public Person(string Name, SexEnum Sex)
    {
      this.Name = Name;
      this.Sex = Sex;
    }
  }
}

Many thanks in advance

回答1:

You should use "Style" triggers instead of "TextBlock.Triggers"

use this XAML:

<Window x:Class="ComboBoxColour.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Orientation="Vertical">
        <ComboBox ItemsSource="{Binding People}" Width="100" Height="20">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Name="somePerson" Text="{Binding Path=Name}">
                        <TextBlock.Style>
                            <Style TargetType="TextBlock">
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding Path=Sex}" Value="Male">
                                        <DataTrigger.Setters>
                                            <Setter Property="Foreground" Value="blue"/>
                                        </DataTrigger.Setters>
                                    </DataTrigger>
                                    <DataTrigger Binding="{Binding Path=Sex}" Value="Female">
                                        <DataTrigger.Setters>
                                            <Setter Property="Foreground" Value="Pink"/>
                                        </DataTrigger.Setters>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </TextBlock.Style>
                    </TextBlock>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </StackPanel>
</Window>

Now you'll have blue for male and pink for female.



回答2:

Use ItemContainerStyle instead of ItemTemplate:

    <ComboBox ItemsSource="{Binding People}" Width="100" Height="20">
        <ComboBox.ItemContainerStyle>
            <Style TargetType="ComboBoxItem">
                <Setter Property="Foreground" Value="Pink" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=Sex}" Value="Male">
                        <Setter Property="Foreground" Value="Blue" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ComboBox.ItemContainerStyle>
    </ComboBox>