根据值更改DataGrid单元格颜色


72

我有一个WPF数据网格,我想要根据值分配不同的单元格颜色。我的xaml上有以下代码

Style TargetType="DataGridCell"

但不是只选择一个单元格而是选择所有行?我想念什么?


2
您可以为您的方案发布示例代码吗?那会有所帮助。顺便说一句,一种方法是将datagridcell的background属性与该单元格的值绑定,然后使用转换器(将值转换为颜色)。
publicgk 2011年

Answers:


150

如果您尝试DataGrid.CellStyle将DataContext设置为该行,那么如果您要基于一个单元格更改颜色,那么在特定的列中进行更改可能是最容易的,尤其是因为列的内容可能不同,例如TextBlocks,ComboBoxes和CheckBoxes 。以下是设置所有单元点亮绿色,其中的一个例子NameJohn

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

屏幕截图


您也可以使用aValueConverter更改颜色。

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(nameof(Name));
            OnPropertyChanged(nameof(NameBrush));
        }
    }
}

public Brush NameBrush
{
    get
    {
        switch (Name)
        {
            case "John":
                return Brushes.LightGreen;
            default:
                break;
        }

        return Brushes.Transparent;
    }
}

嗨,HB,谢谢你或多或少我想要的东西,改变它的单元格,但要根据一个值来改变它,必须看一下值转换器,并与您发送给我的这个代码示例联系起来,但是我认为它是正确的方向,你有我在说什么的例子吗?感谢您
CPM

1
我现在可以根据单元格的值使用浅绿色,但是要使用值转换器来实现,我不想定义value =“ john”想要被触发并根据我将以编程方式设置的条件来设置颜色(cs 。文件C#),希望我做我自己clear.Thankü非常对我的帮助
CPM

关于SO的大量问题说明了如何使用值转换器,您确实可以进行一些搜索。编辑我的答案以显示等效值转换器。
HB

我已经做到了,我已经正确实施了一个cla,但是它不能正常工作,这就是为什么问您**,namespace GridCellColor { public class MyValueConverter : IValueConverter { #region IValueConverter Members object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){ if (Convert.ToInt32(value) > 0) return 10; else if (Convert.ToInt32(value) == 0) return 0; else return -1; }但是却不能正常工作,为什么我问您是否仍然有任何示例感谢您的答复
CPM

该类将您输入的整数转换为另一个整数,该如何为背景着色?您需要一个返回的转换器Brush
HB

22

如果您需要使用一定数量的列进行此操作,那么HB的方法是最好的。但是,如果直到运行时您都不知道要处理多少列,那么下面的代码[read: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>

1
Brushes.Red无济于事,但是"#" + color.Name。想法肯定是你的。谢谢
Moumit '17

4

这可能对您有帮助。但是,这不是股票WPF数据网格。

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

2

只是放

<Style TargetType="{x:DataGridCell}" >

但是请注意,这将针对您所有的单元格(您将针对类型的所有对象DataGridCell)。如果要根据单元格类型放置样式,建议您使用DataTemplateSelector

可以在Christian Mosers的DataGrid教程中找到一个很好的例子:

http://www.wpftutorial.net/DataGrid.html#rowDetails

玩得开心 :)


嗨,大马士革,谢谢您的回复,我有DatagridCell的TargetType,您说对了,因为它影响了我的整行。我希望仅一个单元格受到影响,具体取决于该单元格的值。我怎样才能做到这一点?
CPM

实际上,这取决于您的情况。您在我给您的链接上看到示例了吗?有一个非常清楚的示例,说明如何根据对象类型选择样式(在示例中:男孩还是女孩)。您的问题是否类似?
大马士革

没有类似的原因,因为我想只选择一个单元格,而不要选择整个行,因为在示例中它被播种了。
CPM

2

在我的情况下,转换器必须返回字符串值。我不知道为什么,但是有效。

* .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;
}

1
        // 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;

我希望它在运行时完成。我将datagrid与datatable绑定到窗口load.so上怎么办?
Vivek Parikh 2013年


1

基于“ Cassio Borghi”的回答。使用此方法,根本不需要更改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);
        }

-1

为此请在代码隐藏(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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.