2017-02-15 45 views
0

在WPF項目中,我對DataGrid進行了一些重新編排DataGridColumnHeaders,其中顯示ComboBox每個DataGridColumnHeader。當用戶從ComboBox中選擇SelectionChanged處理程序(在後面的代碼中)時,將使用最新的選擇更新MainWindowViewModel上的Array,ColumnOptionViewModel對象。此時,如果此數組中有任何重複的選擇,則會出現一些代碼,然後在ColumnOptionViewModel上設置重複的IsDuplicate布爾屬性。這個想法是,一個DataTrigger拿起在IsDuplicate的變化和改變TextBlockBackgroundItemTemplateDataTemplate對重複ComboBox年代到RedWPF:DataTrigger not firing

但是,此觸發器未觸發。 IsDuplicate屬性設置正常,其他一切按預期工作。

有沒有人有任何想法我做錯了什麼?

非常感謝您的任何幫助。

下面是窗口的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; 
     } 
    } 
} 

MainWindowViewModel:

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; } 
    } 
} 

ColumnOptionViewModel:

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(); 
     } 
    } 
} 

編輯:

ViewModelBase:

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

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

您可以檢查是否改變文本框的任何其他財產datatrigger(如fontWeight設置工作粗體)? – Arie

+0

@Arie,嘗試將FontWeight更改爲Bold,但仍未開始。 – Cleve

+0

你的'OnPropertyChanged'方法是如何實現的?你沒有傳遞屬性的名稱,所以它可能是問題在那裏(有沒有參數的實現,但只是爲了確定)。 – Shadowed

回答

1

如果你想綁定到SelectedItemIsDuplicate財產在ComboBox你可以使用一個RelativeSource

你也應該在DataTriggerValue屬性設置爲true/false,具體取決於當你想TextBlockBackground屬性被設置爲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> 
+0

嗨@ mm8,它是缺少的'價值'屬性是問題所在。謝謝! – Cleve

+0

Hi @ mm8,你知道爲什麼當我通過在'TextBlock'和Triggers部分放一個'Border'來擴展'DataTemplate'時,我得到3個構建錯誤?一個是'成員'觸發器'不被識別或訪問'。第二種是'在'DataTemplate'類型中未找到可附加屬性'觸發器'。第三個是'附加屬性DataTemplate.Triggers'沒有在'Border'或其基類之一上定義。我懷疑錯誤3是最有幫助的,但我不確定我需要對XAML執行什麼操作才能解決此問題?你能幫忙嗎?謝謝。 – Cleve

+0

嗨,我發現如果我將'Trigger'作爲@Arie建議直接應用於'TextBlock',那麼一切都按預期工作,所以我可以在'DataTemplate'中有一個'Border'。仍然不確定發生了什麼事情! – Cleve

1

由於@ MM8表示,沒有在您的DataTrigger中選擇Value

如果不工作,你可以嘗試使用直接對Trigger代替TextBlockDataTemplate.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> 

此外,在控制具有可選項目的背景和前景值可能會非常棘手。例如,您可能要禁用默認選擇顏色(不幸的是,那麼你將不得不管理選擇/注重後臺自己):

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

Hi @Arie,謝謝你的幫助。這是缺少的「價值」屬性是問題所在。 – Cleve

+0

Hi @Arie,感謝您的提示,直接在'TextBlock'上應用觸發器,因爲它幫助我進一步解決了遇到的下一個問題(請參閱下面的@ mm8答案中的註釋)。謝謝。 – Cleve