2017-02-15 7 views
0

In einem WPF-Projekt habe ich einige DataGridColumnHeaders von einem DataGrid neugestylt, die ein ComboBox für jedes DataGridColumnHeader zeigen. Wenn der Benutzer wählt ComboBox 's SelectionChanged Handler (im Code hinter) aktualisiert eine Array von ColumnOptionViewModel Objekte auf der MainWindowViewModel mit der neuesten Auswahl. An diesem Punkt funktioniert auch Code, wenn in diesem Array doppelte Auswahlen vorhanden sind, und setzt dann eine boolesche IsDuplicate-Eigenschaft auf den ColumnOptionViewModel, die Duplikate sind. Die Idee ist, dass ein DataTrigger abholt die Änderung in IsDuplicate und ändert die Background ein TextBlock im DataTemplate der ItemTemplate für die doppelten ComboBox ‚s zu Red.WPF: DataTrigger nicht feuern

Dieser Auslöser wird jedoch nicht ausgelöst. Die IsDuplicate Eigenschaften sind in Ordnung, und alles andere funktioniert wie erwartet.

Hat jemand eine Idee, was ich falsch mache?

Vielen Dank im Voraus für jede Hilfe. Hier

ist das XAML für das Fenster:

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

Code hinter:

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

EDIT:

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

können Sie überprüfen, ob eine andere Eigenschaft Textbox Wechsel in Datatrigger funktioniert (zB Fontweight zu Bold) – Arie

+0

@Arie, versucht, FontWeight auf Fett zu ändern, wie vorgeschlagen, aber immer noch nicht feuernd. – Cleve

+0

Wie wird Ihre 'OnPropertyChanged' Methode implementiert? Sie geben den Namen der Eigenschaft nicht weiter, so dass es dort möglicherweise ein Problem gibt (es gibt Implementierungen ohne Parameter, aber nur um sicher zu sein). – Shadowed

Antwort

1

Wenn Sie die IsDuplicate Eigenschaft des SelectedItem in der ComboBox Sie eine RelativeSource verwenden könnte zu binden versuchen.

Sie sollten setzen auch die Value Eigenschaft des DataTrigger auf true/false je nachdem, wann Sie die Background Eigenschaft des TextBlock wollen Red gesetzt werden:

<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

Hallo @ mm8, es war die fehlende 'Value' Eigenschaft, die das Problem war. Vielen Dank! – Cleve

+0

Hallo @ mm8, weißt du, warum, wenn ich die 'DataTemplate' erweitere, indem ich einen 'Border' um den'TextBlock'- und Triggerbereich bringe, bekomme ich 3 Buildfehler? Einer ist "Das Mitglied" Auslöser "ist nicht anerkannt oder zugänglich". Die zweite ist 'Die anfüge Eigenschaft' Triggers 'wurde nicht im Typ' DataTemplate 'gefunden. Die dritte ist 'Die angefügte Eigenschaft' DataTemplate.Triggers 'ist nicht in' Border 'oder einer ihrer Basisklassen definiert. Ich vermute, dass Err 3 am hilfreichsten ist, aber ich bin mir nicht sicher, was ich mit dem XAML machen muss, um das zu umgehen? Könntest du damit helfen? Vielen Dank. – Cleve

+0

Hallo, ich habe festgestellt, dass, wenn ich den 'Trigger' direkt auf den' TextBlock' anwende, wie @Arie vorgeschlagen hat, dann funktioniert alles wie erwartet, so dass ich dann einen 'Border' im' DataTemplate' habe. Immer noch nicht sicher, was los war! – Cleve

1

Als @ mm8 sagte, die Value ist in Ihrer DataTrigger nicht ausgewählt.

Wenn das nicht funktioniert, können Sie versuchen Trigger mit direkt auf TextBlock statt 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> 

Auch Hintergrund- und Vordergrund Werte in der Kontrollgruppe, die auswählbaren Elemente haben kann schwierig sein.Zum Beispiel können Sie Standard-Auswahl Farben deaktivieren (leider dann haben Sie ausgewählt/fokussierten Hintergrund selbst verwalten):

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

Hallo @Arie, danke für deine Hilfe. Es war die fehlende Value-Eigenschaft, die das Problem war. – Cleve

+0

Hallo @Arie, danke für deinen Tipp mit dem Trigger direkt auf den 'TextBlock', da es mir weiter mit dem nächsten Problem geholfen hat (siehe Kommentare unten in @ mm8 Antwort). Vielen Dank. – Cleve

Verwandte Themen