Изменение цвета ячейки DataGrid на основе значений
У меня есть WPF datagrid, и я хочу разные цвета ячеек в соответствии со значениями. Я получил ниже код на моем xaml
Style TargetType="DataGridCell"
но вместо выбора только ячейки выбирается вся строка? Чего мне не хватает?
7 ответов:
если вы попытаетесь установить
DataGrid.CellStyle
DataContext будет строкой, поэтому, если вы хотите изменить цвет на основе одной ячейки, это может быть проще всего сделать в определенных столбцах, тем более что столбцы могут иметь различное содержимое, например текстовые блоки, комбо-боксы и флажки. Вот пример установки всех ячеек светло-зеленого цвета, гдеName
иJohn
:<DataGridTextColumn Binding="{Binding Name}"> <DataGridTextColumn.ElementStyle> <Style TargetType="{x:Type TextBlock}"> <Style.Triggers> <Trigger Property="Text" Value="John"> <Setter Property="Background" Value="LightGreen"/> </Trigger> </Style.Triggers> </Style> </DataGridTextColumn.ElementStyle> </DataGridTextColumn>
вы также можете использовать
ValueConverter
изменить цвет.public class NameToBrushConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { string input = value as string; switch (input) { case "John": return Brushes.LightGreen; default: return DependencyProperty.UnsetValue; } } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); } }
использование:
<Window.Resources> <local:NameToBrushConverter x:Key="NameToBrushConverter"/> </Window.Resources> ... <DataGridTextColumn Binding="{Binding Name}"> <DataGridTextColumn.ElementStyle> <Style TargetType="{x:Type TextBlock}"> <Setter Property="Background" Value="{Binding Name, Converter={StaticResource NameToBrushConverter}}"/> </Style> </DataGridTextColumn.ElementStyle> </DataGridTextColumn>
еще один вариант-напрямую связывать
Background
к свойству, которое возвращает соответственно окрашенную кисть. Вам придется запускать уведомления об изменении свойств в установщиках свойств, от которых зависит цвет.например
public string Name { get { return _name; } set { if (_name != value) { _name = value; OnPropertyChanged("Name"); OnPropertyChanged("NameBrush"); } } } public Brush NameBrush { get { switch (Name) { case "John": return Brushes.LightGreen; default: break; } return Brushes.Transparent; } }
Если вам нужно сделать это с заданным количеством столбцов, способ H. B. лучше всего. Но если вы не знаете, сколько столбцов вы имеете дело с до времени выполнения, то ниже код [читать: hack] будет работать. Я не уверен, что есть лучшее решение с неизвестным количеством столбцов. Мне потребовалось два дня, чтобы работать над этим, чтобы получить его, поэтому я придерживаюсь его независимо.
C#
public class ValueToBrushConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { int input; try { DataGridCell dgc = (DataGridCell)value; System.Data.DataRowView rowView = (System.Data.DataRowView)dgc.DataContext; input = (int)rowView.Row.ItemArray[dgc.Column.DisplayIndex]; } catch (InvalidCastException e) { return DependencyProperty.UnsetValue; } switch (input) { case 1: return Brushes.Red; case 2: return Brushes.White; case 3: return Brushes.Blue; default: return DependencyProperty.UnsetValue; } } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); } }
XAML
<UserControl.Resources> <conv:ValueToBrushConverter x:Key="ValueToBrushConverter"/> <Style x:Key="CellStyle" TargetType="DataGridCell"> <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource ValueToBrushConverter}}" /> </Style> </UserControl.Resources> <DataGrid x:Name="dataGrid" CellStyle="{StaticResource CellStyle}"> </DataGrid>
просто вместо того, чтобы поставить
<Style TargetType="{x:DataGridCell}" >
но будьте осторожны, что это будет нацелено на все ваши клетки (вы нацелены на все объекты типа
DataGridCell
) Если вы хотите поместить стиль в соответствии с типом ячейки, я бы рекомендовал вам использоватьDataTemplateSelector
хороший пример можно найти в христианской Mosers' DataGrid с учебником:
http://www.wpftutorial.net/DataGrid.html#rowDetails
удачи :)
в моем случае преобразователь должен возвращать строковое значение. Я не знаю почему, но это работает.
*.xaml (общий файл стиля, который включен в другие файлы xaml)
<Style TargetType="DataGridCell"> <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource ValueToBrushConverter}}" /> </Style>
*.cs
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { Color color = VSColorTheme.GetThemedColor(EnvironmentColors.ToolWindowBackgroundColorKey); return "#" + color.Name; }
Это может помочь вам. Однако это не фондовый WPF datagrid.
Я использовал DevExpress с пользовательским поведением ColorFormatter. Я не мог найти ничего на рынке, что сделало бы это из коробки. Это заняло у меня несколько дней, чтобы развиться. Мой код аттачед ниже, надеюсь, это поможет кому-то там.
Edit: я использовал модели просмотра POCO и MVVM, однако вы можете изменить это, чтобы не использовать POCO, если вы жаждать.
Viewmodel.cs
namespace ViewModel { [POCOViewModel] public class Table2DViewModel { public ITable2DView Table2DView { get; set; } public DataTable ItemsTable { get; set; } public Table2DViewModel() { } public Table2DViewModel(MainViewModel mainViewModel, ITable2DView table2DView) : base(mainViewModel) { Table2DView = table2DView; CreateTable(); } private void CreateTable() { var dt = new DataTable(); var xAxisStrings = new string[]{"X1","X2","X3"}; var yAxisStrings = new string[]{"Y1","Y2","Y3"}; //TODO determine your min, max number for your colours var minValue = 0; var maxValue = 100; Table2DView.SetColorFormatter(minValue,maxValue, null); //Add the columns dt.Columns.Add(" ", typeof(string)); foreach (var x in xAxisStrings) dt.Columns.Add(x, typeof(double)); //Add all the values double z = 0; for (var y = 0; y < yAxisStrings.Length; y++) { var dr = dt.NewRow(); dr[" "] = yAxisStrings[y]; for (var x = 0; x < xAxisStrings.Length; x++) { //TODO put your actual values here! dr[xAxisStrings[x]] = z++; //Add a random values } dt.Rows.Add(dr); } ItemsTable = dt; } public static Table2DViewModel Create(MainViewModel mainViewModel, ITable2DView table2DView) { var factory = ViewModelSource.Factory((MainViewModel mainVm, ITable2DView view) => new Table2DViewModel(mainVm, view)); return factory(mainViewModel, table2DView); } } }
IView.cs
namespace Interfaces { public interface ITable2DView { void SetColorFormatter(float minValue, float maxValue, ColorScaleFormat colorScaleFormat); } }
вид.код XAML.cs
namespace View { public partial class Table2DView : ITable2DView { public Table2DView() { InitializeComponent(); } static ColorScaleFormat defaultColorScaleFormat = new ColorScaleFormat { ColorMin = (Color)ColorConverter.ConvertFromString("#FFF8696B"), ColorMiddle = (Color)ColorConverter.ConvertFromString("#FFFFEB84"), ColorMax = (Color)ColorConverter.ConvertFromString("#FF63BE7B") }; public void SetColorFormatter(float minValue, float maxValue, ColorScaleFormat colorScaleFormat = null) { if (colorScaleFormat == null) colorScaleFormat = defaultColorScaleFormat; ConditionBehavior.MinValue = minValue; ConditionBehavior.MaxValue = maxValue; ConditionBehavior.ColorScaleFormat = colorScaleFormat; } } }
DynamicConditionBehavior.cs
namespace Behaviors { public class DynamicConditionBehavior : Behavior<GridControl> { GridControl Grid => AssociatedObject; protected override void OnAttached() { base.OnAttached(); Grid.ItemsSourceChanged += OnItemsSourceChanged; } protected override void OnDetaching() { Grid.ItemsSourceChanged -= OnItemsSourceChanged; base.OnDetaching(); } public ColorScaleFormat ColorScaleFormat { get; set;} public float MinValue { get; set; } public float MaxValue { get; set; } private void OnItemsSourceChanged(object sender, EventArgs e) { var view = Grid.View as TableView; if (view == null) return; view.FormatConditions.Clear(); foreach (var col in Grid.Columns) { view.FormatConditions.Add(new ColorScaleFormatCondition { MinValue = MinValue, MaxValue = MaxValue, FieldName = col.FieldName, Format = ColorScaleFormat, }); } } } }
вид.xaml
<UserControl x:Class="View" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" xmlns:ViewModels="clr-namespace:ViewModel" xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid" xmlns:behaviors="clr-namespace:Behaviors" xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking" DataContext="{dxmvvm:ViewModelSource Type={x:Type ViewModels:ViewModel}}" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="800"> <UserControl.Resources> <Style TargetType="{x:Type dxg:GridColumn}"> <Setter Property="Width" Value="50"/> <Setter Property="HorizontalHeaderContentAlignment" Value="Center"/> </Style> <Style TargetType="{x:Type dxg:HeaderItemsControl}"> <Setter Property="FontWeight" Value="DemiBold"/> </Style> </UserControl.Resources> <!--<dxmvvm:Interaction.Behaviors> <dxmvvm:EventToCommand EventName="" Command="{Binding OnLoadedCommand}"/> </dxmvvm:Interaction.Behaviors>--> <dxg:GridControl ItemsSource="{Binding ItemsTable}" AutoGenerateColumns="AddNew" EnableSmartColumnsGeneration="True"> <dxmvvm:Interaction.Behaviors > <behaviors:DynamicConditionBehavior x:Name="ConditionBehavior" /> </dxmvvm:Interaction.Behaviors> <dxg:GridControl.View> <dxg:TableView ShowGroupPanel="False" AllowPerPixelScrolling="True"/> </dxg:GridControl.View> </dxg:GridControl> </UserControl>
// Example: Adding a converter to a column (C#) Style styleReading = new Style(typeof(TextBlock)); Setter s = new Setter(); s.Property = TextBlock.ForegroundProperty; Binding b = new Binding(); b.RelativeSource = RelativeSource.Self; b.Path = new PropertyPath(TextBlock.TextProperty); b.Converter = new ReadingForegroundSetter(); s.Value = b; styleReading.Setters.Add(s); col.ElementStyle = styleReading;
чтобы сделать это в коде позади (VB.NET)
Dim txtCol As New DataGridTextColumn Dim style As New Style(GetType(TextBlock)) Dim tri As New Trigger With {.Property = TextBlock.TextProperty, .Value = "John"} tri.Setters.Add(New Setter With {.Property = TextBlock.BackgroundProperty, .Value = Brushes.Green}) style.Triggers.Add(tri) xtCol.ElementStyle = style