2017-02-15 14 views
0

В проекте WPF у меня есть рестайлинг DataGridColumnHeaders из DataGrid, который показывает ComboBox для каждого DataGridColumnHeader. Когда пользователь выбирает ComboBox, обработчик SelectionChanged (в коде позади) обновляет ArrayColumnOptionViewModel объектов на MainWindowViewModel с самым новым выбором. В этот момент некоторый код также работает, если в этом массиве есть дубликаты, а затем задает логическое свойство IsDuplicate на ColumnOptionViewModel, которые являются дубликатами. Идея заключается в том, что DataTrigger поднимает изменения в IsDuplicate и изменяет Background в виде TextBlock в DataTemplate в ItemTemplate для дублирующих ComboBox-х до Red.WPF: DataTrigger не работает

Однако этот триггер не срабатывает. Свойства 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(); 
     } 
    } 
} 

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

вы можете проверить, если изменения любого другого свойства текстового поля работает в DataTrigger (например FontWeight для Жирных)? – Arie

+0

@Arie, попробовал изменить FontWeight на Bold, как и предполагалось, но все же не стрелял. – Cleve

+0

Как реализован метод 'OnPropertyChanged'? Вы не передаете имя свойства, так что это может быть проблема (существуют реализации без параметра, но для этого обязательно). – Shadowed

ответ

1

Если вы пытаетесь привязать к IsDuplicate свойству SelectedItem в ComboBox вы могли бы использовать RelativeSource.

Вы также должны установить Value свойство DataTrigger истина/ложь в зависимости от того, когда вы хотите 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> 
+0

Привет @ mm8, это недоставало свойства Value. Благодаря! – Cleve

+0

Привет @ mm8, вы знаете, почему, когда я расширяю 'DataTemplate', помещая' Border' вокруг секции TextBlock и Triggers, я получаю 3 ошибки сборки? Один из них: «Элемент« Триггеры »не распознается и не доступен». Второй вариант: «Свойство« Триггеры », которое можно подключить, не найдено в типе« DataTemplate ». Третий - это «Вложенное свойство» DataTemplate.Triggers' не определено в «Border» или одном из его базовых классов. Я подозреваю, что ошибка 3 является самой полезной, но я не уверен, что мне нужно сделать для XAML, чтобы обойти это? Не могли бы вы помочь с этим? Благодарю. – Cleve

+0

Привет, я с тех пор обнаружил, что если я применил 'Trigger' непосредственно к' TextBlock', как предлагал @Arie, тогда все работает так, как ожидалось, поэтому я могу иметь 'Border' в' DataTemplate'. Все еще не уверен, что происходит! – Cleve

1

Как @ MM8 говорил, Value не выбран в вашем DataTrigger.

Если это не работает, вы можете попробовать использовать Trigger непосредственно на TextBlock вместо 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> 

Кроме того, фон и передний план значение в элементах управления, которые имеют выбираемые элементы может быть сложнее.Например, вы можете отключить цвета выбора по умолчанию (к сожалению, то вам придется управлять выбранным/целенаправленным фоном самостоятельно):

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

Привет @ Арье, спасибо за вашу помощь. Проблема была в недостатке свойства Value. – Cleve

+0

Привет @Arie, спасибо за подсказку с применением триггера непосредственно на 'TextBlock', так как это помогло мне в дальнейшем со следующей проблемой, с которой я столкнулся (см. Комментарии ниже в ответе @ mm8). Спасибо. – Cleve

 Смежные вопросы

  • Нет связанных вопросов^_^