У меня есть datagrid WPF, и я хочу, чтобы разные цвета ячеек соответствовали значениям. У меня есть код на моем xaml
Style TargetType="DataGridCell"
но вместо выбора ячейки выбирается только строка? Что мне не хватает?
У меня есть datagrid WPF, и я хочу, чтобы разные цвета ячеек соответствовали значениям. У меня есть код на моем xaml
Style TargetType="DataGridCell"
но вместо выбора ячейки выбирается только строка? Что мне не хватает?
Если вы попытаетесь установить DataGrid.CellStyle, то DataContext будет строкой, поэтому, если вы хотите изменить цвет на основе одной ячейки, это может быть проще всего сделать в определенных столбцах, тем более, что столбцы могут иметь различное содержимое, таких как TextBlocks, ComboBoxes и CheckBoxes. Вот пример установки всех ячеек зеленого цвета, где 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. путь лучше. Но если вы не знаете, сколько столбцов вы имеете в виду до выполнения, тогда будет работать следующий код [read: hack]. Я не уверен, есть ли лучшее решение с неизвестным количеством столбцов. Мне потребовалось два дня, чтобы поработать над этим, чтобы получить его, поэтому я придерживаюсь его независимо.
С#
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
Хороший пример можно найти в учебнике по 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;
}
		Это может помочь вам. Однако это не фондовый WPat datagrid.
Я использовал DevExpress с пользовательским поведением ColorFormatter. Я не мог найти ничего на рынке, который сделал это из коробки. Мне потребовалось несколько дней для развития. Мой код приведен ниже, надеюсь, это поможет кому-то там.
Изменить: я использовал модели просмотра 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);
        }
    }
View.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,
                });
            }
        }
    }
}
View.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;
		Основано на ответе "Кассио Борги". При использовании этого метода нет необходимости менять XAML вообще.
        DataGridTextColumn colNameStatus2 = new DataGridTextColumn();
        colNameStatus2.Header = "Status";
        colNameStatus2.MinWidth = 100;
        colNameStatus2.Binding = new Binding("Status");
        grdComputer_Servives.Columns.Add(colNameStatus2);
        Style style = new Style(typeof(TextBlock));
        Trigger running = new Trigger() { Property = TextBlock.TextProperty, Value = "Running" };
        Trigger stopped = new Trigger() { Property = TextBlock.TextProperty, Value = "Stopped" };
        stopped.Setters.Add(new Setter() { Property = TextBlock.BackgroundProperty, Value = Brushes.Blue });
        running.Setters.Add(new Setter() { Property = TextBlock.BackgroundProperty, Value = Brushes.Green });
        style.Triggers.Add(running);
        style.Triggers.Add(stopped);
        colNameStatus2.ElementStyle = style;
        foreach (var Service in computerResult)
        {
            var RowName = Service;  
            grdComputer_Servives.Items.Add(RowName);
        }
		Чтобы сделать это в коде позади (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