Как изменить цвет фона ячейки с помощью WPF Toolkit Datagrid

Я использую набор инструментов WPF datagrid, и я хотел бы установить цвет фона ячейки, а не строки, в зависимости от содержимого ячейки.

Для простоты предположим, что столбец называется Foo, и я бы хотел, чтобы фон ячейки был синим, когда Foo равно 1, красным, когда Foo равно 2, желтым, когда Foo равно 3, и зеленым, когда Foo больше 3 .

Если я смогу это сделать, я почти уверен, что смогу решить любой из более сложных случаев, с которыми мне придется иметь дело.


person Jonathan Beerhalter    schedule 16.11.2009    source источник


Ответы (4)


Вы делаете это с помощью стилей и триггеров данных. Просто установите для ElementStyle свойство фона по умолчанию, в данном случае Green, и добавьте DataTriggers для других случаев:

<DataGridTextColumn Binding="{Binding WhateverIWantToDisplay}" >
  <DataGridTextColumn.ElementStyle>
    <Style TargetType="{x:Type TextBlock}">

      <Setter Property="Background" Value="Green" />

      <Style.Triggers>
        <DataTrigger Binding="{Binding Foo}" Value="1">
          <Setter Property="Background" Value="Blue" />
        </DataTrigger>

        <DataTrigger Binding="{Binding Foo}" Value="2">
          <Setter Property="Background" Value="Red" />
        </DataTrigger>

        <DataTrigger Binding="{Binding Foo}" Value="2">
          <Setter Property="Background" Value="Yellow" />
        </DataTrigger>

      </Style.Triggers>
    </Style>
  </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

Другой подход - использовать привязку с конвертером:

<DataGridTextColumn Binding="{Binding WhateverIWantToDisplay}" >
  <DataGridTextColumn.ElementStyle>
    <Style TargetType="{x:Type TextBlock}">

      <Setter Property="Background"
        Value="{Binding Foo, Converter={x:Static my:FooToColorConverter.Instance}}" />

    </Style>
  </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

с этим конвертером:

public class FooToColorConverter : IValueConverter
{
  public static readonly IValueConverter Instance = new FooToColorConverter();
  public object Convert(object value, ...
  {
    int foo = (int)value;
    return
      foo==1 ? Brushes.Blue :
      foo==2 ? Brushes.Red :
      foo==3 ? Brushes.Yellow :
      foo>3 ? Brushes.Green :
        Brushes.Transparent;  // For foo<1
  }
  public object ConvertBack(...
  {
    throw new NotImplementedException();
  }
}

Обратите внимание, что ответ, который дал serge_gubenko, также будет работать, но только если значение вашего свойства Foo никогда не меняется. Это связано с тем, что метод получения свойства Color будет вызываться только один раз. Его решение можно улучшить, изменив Color на DependencyProperty, доступное только для чтения, и обновив его всякий раз, когда назначается Foo, но, как правило, иметь в модели данных специфичную для пользовательского интерфейса информацию, такую ​​как цвета, - плохая идея, поэтому это не рекомендуется.

person Ray Burns    schedule 17.11.2009
comment
Большое спасибо. Мне так неприятно работать с WPF, потому что он имеет тенденцию скрывать ошибки и просто ничего не делать, если у вас нет правильного кода. Но когда он работает и когда вы знаете, что делаете, его молниеносно легко и быстро использовать. Я бы честно сказал, что у WPF самая крутая кривая обучения из всех технологий, которые я использовал. В любом случае, еще раз спасибо. Я выбрал конвертер, потому что он дает мне максимальную гибкость. - person Jonathan Beerhalter; 17.11.2009

Один из способов сделать это - определить ElementStyle для столбца, а затем привязать фон текстового блока к свойству цвета элемента данных за строкой таблицы данных. Вот пример:

DataGridTextColumn xaml:

<DataGridTextColumn Width="SizeToCells"   
                       MinWidth="150" 
                       Binding="{Binding Name}">

    <DataGridTextColumn.ElementStyle>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="TextBlock.Background" Value="{Binding Color}" />
        </Style>
    </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

объявление элемента данных:

public class TestItem
{
    public TestItem(int foo)
    {
        Foo = foo;
    }

    public int Foo { get; set; }
    public Brush Color
    {
        get
        {
            Color color = Colors.Green;
            switch (Foo)
            {
                case 1: color = Colors.Red; break;
                case 2: color = Colors.Yellow; break; 
            }
            return new SolidColorBrush(color);
        }
    }
}

надеюсь, что это поможет, с уважением

person serge_gubenko    schedule 17.11.2009
comment
Это не сработает, если значение Foo когда-либо изменится после отображения сетки: цвет ячейки не будет обновляться. См. Мой ответ для более подробной информации. - person Ray Burns; 17.11.2009
comment
И ни то, ни другое, если Foo изменяется (например, из-за привязки данных) при отображении сетки. - person greenoldman; 25.08.2010
comment
Ну, это старый, но все, что вам нужно исправить, - это реализовать INotifyPropertyChanged с помощью класса TestItem, чтобы уведомить пользовательский интерфейс об изменениях цвета. - person Tafari; 28.10.2013

Немного другой подход - вместо нацеливания на элемент TextBlock, который часто оставляет границу вокруг элемента управления, на сам DataGridCell. В моем случае у меня уже был стиль, который я хотел унаследовать, мне просто нужно было изменить цвета фона в зависимости от значения:

<DataGridTextColumn 
    Width="*"
    Header="Status"
    Binding="{Binding EventStatus, Converter={StaticResource DescriptionAttributeConverter}}"
    HeaderStyle="{StaticResource DataGridColumnHeaderStyleCenterAligned}">

    <DataGridTextColumn.CellStyle>
        <Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource DataGridCellStyleCenterAligned}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding EventStatus}" Value="1">
                    <Setter Property="Background" Value="Green" />
                </DataTrigger>

                <DataTrigger Binding="{Binding EventStatus}" Value="2">
                    <Setter Property="Background" Value="Red" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

Может быть, мне пригодится моя ситуация.

person Pseudonymous    schedule 13.06.2019

Serge_gubenko будет хорошо работать, если ваш элемент наследуется от INotifyPropertyChanged, тогда когда ваше свойство изменит вызов на NotifyPropertyChanged ("yourproperty")

person Samuel    schedule 11.04.2012