WPF:DataTrigger 未触发

WPF: DataTrigger not firing

在一个 WPF 项目中,我重新设计了 DataGridDataGridColumnHeaders,其中每个 DataGridColumnHeader 显示了 ComboBox。当用户从 ComboBox 中选择时,SelectionChanged 处理程序(在后面的代码中)使用最新的 MainWindowViewModel 上的 ColumnOptionViewModel 个对象更新 Array选择。

在这一点上,如果这个数组中有任何重复的选择,一些代码也会起作用,然后在重复的 ColumnOptionViewModel 上设置一个 IsDuplicate 布尔值 属性。这个想法是 DataTrigger 获取 IsDuplicate 中的变化,并在 ItemTemplateDataTemplate 中改变 TextBlockBackground重复的 ComboBoxRed

但是,这个触发器没有触发。 IsDuplicate 属性设置正常,其他一切都按预期工作。我做错了什么?

这是 Window 的 XAML:

<Window x:Class="TestDataGrid.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:TestDataGrid"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">

 <Grid>
    <DataGrid Grid.Row="1" x:Name="dataGrid" ItemsSource="{Binding Records}">
        <DataGrid.ColumnHeaderStyle>
            <Style TargetType="DataGridColumnHeader">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <StackPanel>
                                <ComboBox x:Name="cbo"
                                          ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},Path=DataContext.ColumnOptions}"
                                          SelectionChanged="cbo_SelectionChanged">

                                     <ComboBox.ItemTemplate>
                                        <DataTemplate>
                                            <TextBlock x:Name="txt" Text="{Binding Name}"/>
                                            <DataTemplate.Triggers>
                                                <DataTrigger Binding="{Binding ElementName=cbo, Path=SelectedItem.IsDuplicate}">
                                                    <Setter TargetName="txt" Property="Background" Value="Red"/>
                                                </DataTrigger>
                                            </DataTemplate.Triggers>
                                        </DataTemplate>
                                    </ComboBox.ItemTemplate>
                                </ComboBox>
                            </StackPanel>   
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </DataGrid.ColumnHeaderStyle>
    </DataGrid>    
</Grid>

代码隐藏:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new MainWindowViewModel(RecordProvider.GetRecords());
    }

    private void cbo_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var vm = (MainWindowViewModel)DataContext;

        var selectionChangedCombo = (ComboBox)e.Source;

        var dataGridColumnHeader = selectionChangedCombo.TemplatedParent as DataGridColumnHeader;

        vm.ColumnSelections[dataGridColumnHeader.DisplayIndex] = selectionChangedCombo.SelectedItem as ColumnOptionViewModel;

        CheckForDuplicates();

    }

    private void CheckForDuplicates()
    {
        var vm = (MainWindowViewModel)DataContext;

        var duplicates = vm.ColumnSelections.GroupBy(x => x.Name)
            .Where(g => g.Skip(1).Any())
            .SelectMany(g => g);

        foreach (var option in duplicates)
        {
            option.IsDuplicate = true;
        }
    }
}

主要Window视图模型:

public class MainWindowViewModel : ViewModelBase
{
    public ObservableCollection<ColumnOptionViewModel> _columnOptions = new ObservableCollection<ColumnOptionViewModel>();
    public ObservableCollection<RecordViewModel> _records = new ObservableCollection<RecordViewModel>();

    ColumnOptionViewModel[] _columnSelections = new ColumnOptionViewModel[3];

    public MainWindowViewModel(IEnumerable<Record> records)
    {
        foreach (var rec in records)
        {
            Records.Add(new RecordViewModel(rec));
        }

        ColumnOptions.Add(new ColumnOptionViewModel(TestDataGrid.ColumnOptions.ColumnOption1));
        ColumnOptions.Add(new ColumnOptionViewModel(TestDataGrid.ColumnOptions.ColumnOption2));
        ColumnOptions.Add(new ColumnOptionViewModel(TestDataGrid.ColumnOptions.ColumnOption3));

        ColumnSelections[0] = ColumnOptions[0];
        ColumnSelections[1] = ColumnOptions[1];
        ColumnSelections[2] = ColumnOptions[2];

    }

    public ObservableCollection<ColumnOptionViewModel> ColumnOptions
    {
        get { return _columnOptions; }
        set { _columnOptions = value; }
    }

    public ColumnOptionViewModel[] ColumnSelections
    {
        get { return _columnSelections; }
        set { _columnSelections = value; }
    }

    public ObservableCollection<RecordViewModel> Records
    {
        get { return _records; }
        set { _records = value; }
    }
}

列选项视图模型:

public class ColumnOptionViewModel : ViewModelBase
{
    ColumnOptions _colOption;

    public ColumnOptionViewModel(ColumnOptions colOption )
    {
        _colOption = colOption;
    }

    public string Name
    {
        get { return _colOption.ToString(); }
    }

    public override string ToString()
    {
        return Name;
    }

    private bool _isDuplicate = false;
    public bool IsDuplicate
    {
        get { return _isDuplicate; }
        set
        { _isDuplicate = value;
            OnPropertyChanged();
        }
    }
}

编辑:

视图模型库:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

如果您尝试绑定到 ComboBoxSelectedItemIsDuplicate 属性,您可以使用 RelativeSource

您还应该将 DataTriggerValue 属性 设置为 true/false,具体取决于您何时需要 Background 属性 TextBlock 设置为 Red:

<ComboBox x:Name="cbo" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},Path=DataContext.ColumnOptions}"
                  SelectionChanged="cbo_SelectionChanged">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock x:Name="txt" Text="{Binding Name}"/>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=SelectedItem.IsDuplicate, RelativeSource={RelativeSource AncestorType=ComboBox}}" Value="True">
                    <Setter TargetName="txt" Property="Background" Value="Red"/>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

正如@mm8所说,你的DataTrigger中没有选择Value

如果这不起作用,您可以尝试直接在 TextBlock 上使用 Trigger 而不是 DataTemplate.Triggers:

   <TextBlock>
       <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Setter Property="Background" Value="White"/>
                <Style.Triggers>
                   <DataTrigger Binding="{Binding Path=IsDuplicate}" Value="True">
                      <Setter Property="Background" Value="Red"/>
                    </DataTrigger>
                 </Style.Triggers>
              </Style>
         </TextBlock.Style>
      </TextBlock>

此外,具有可选项目的控件中的背景和前景值可能很棘手。例如,您可能想要禁用默认选择颜色(不幸的是,您将不得不自己管理 selected/focused 背景):

        <ComboBox.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
        </ComboBox.Resources>