【问题标题】:Changing background color of cells in DataGrid WPF更改 DataGrid WPF 中单元格的背景颜色
【发布时间】:2018-09-26 19:59:38
【问题描述】:

我使用以下链接在表格中显示我的二维数据:

How to bind an 2D array bool[][] to a WPF DataGrid (one-way)?

Change DataGrid cell colour based on values

除了背景颜色没有改变(甚至没有点击转换器方法)之外,一切都在工作。谁能告诉我这是怎么回事?

下面我发布一个完整的、最小的示例。我不喜欢任何这些想法(例如,使用 DataView 绑定我的 IEnumerable>),因此请随意提出替代方法。我唯一的硬性要求是,在我的实际项目中,数据以 IEnumerable>

的形式给出

代码如下:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        ViewModel vm = new ViewModel();

        List<Column> row1 = new List<Column>()
        {
            new Column(){Make = Make.Ford,OperatingStatus =  OperatingStatus.Broken},
            new Column(){Make = Make.Honda, OperatingStatus = OperatingStatus.Unknown}
        };
        List<Column> row2 = new List<Column>()
        {
            new Column() {Make = Make.GM, OperatingStatus = OperatingStatus.Working},
            new Column() {Make = Make.Toyota, OperatingStatus = OperatingStatus.Broken}
        };

        List<List<Column>> data = new List<List<Column>>();
        data.Add(row1);
        data.Add(row2);
        vm.Data = data;
        DataContext = vm;

    }
}

public enum OperatingStatus
{
    Working = 0,
    Broken = 1,
    Unknown = 2
}

public enum Make
{
    Ford,
    Honda,
    GM,
    Toyota
}

public class Column
{
    public Make Make { get; set; }
    public OperatingStatus OperatingStatus { get; set; }
}
public class ViewModel
{
    public IEnumerable<IEnumerable<Column>>  Data { get; set; }

    public DataView MyDataTable
    {
        get
        {
            var rows = Data.Count();
            var cols = Data.First().Count();
            var t = new DataTable();
            for (var c = 0; c < cols; c++)
            {
                t.Columns.Add(new DataColumn(c.ToString()));
            }

            foreach (var row in Data)
            {
                var newRow = t.NewRow();
                int c = 0;
                foreach (var col in row)                 
                {
                    newRow[c] = col.Make;
                    c++;
                }
                t.Rows.Add(newRow);
            }
            return t.DefaultView;
        }
    }
}

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 "Ford":
                return Brushes.LightGreen;
            case "GM":
                return Brushes.Red;
            case "Toyota":
                return Brushes.Blue;
            case "Honda":
                return Brushes.Yellow;
            default:
                return DependencyProperty.UnsetValue;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

这里是 XAML

<Window x:Class="StackOverFlowDataGridQuestion.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:StackOverFlowDataGridQuestion"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Window.Resources>
    <local:NameToBrushConverter x:Key="NameToBrushConverter"/>
</Window.Resources>
<Grid>
    <ScrollViewer>
        <DataGrid Width="1000"
                  Margin="0"
                  HorizontalAlignment="Left"                   
                  DataContext="{Binding}"                      
                  ItemsSource="{Binding MyDataTable}"      >

            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Make}">
                    <DataGridTextColumn.ElementStyle>
                        <Style TargetType="{x:Type TextBlock}">
                            <Setter Property="Background" Value="{Binding Make, Converter={StaticResource NameToBrushConverter}}"/>
                        </Style>
                    </DataGridTextColumn.ElementStyle>
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    </ScrollViewer>
</Grid>

在尝试了 Nik 的建议并在两个地方将 'Make' 替换为 'Row[0]' 之后,我得到了以下内容,这是进步,因为有一些颜色!如果有更多变化,我会在这里报告。

我本来希望福特广场是绿色的,本田是黄色的,通用是红色的,丰田是蓝色的。更像下面的东西(请原谅我糟糕的标记技巧)。

【问题讨论】:

  • 名称是否不变而其他列不同?假设数组甚至具有可变维度(?)很久以前,我写了一些东西来处理具有一些固定列和任意数量的可变列的对象。我使用了一个视图模型,其中将固定列定义为属性,并为这些列使用了一个 observabledictionary。完全不确定这对你正在做的事情有好处,或者在任何方面都比 Nik 的建议更好。扩展对象是另一种选择。
  • 安迪,我不确定我是否理解你的问题。每列代表一个具有两个属性“Make”和“OperatingStatus”的对象。但是,现在我要求只根据 Make 设置颜色。每行将具有相同数量的列。它需要可配置,以便我可以更改列数,但这不会在一次运行中发生(应用程序必须重新启动)。此外,在实际应用程序中,数据更像是 5000 行和 15 列。但同样,每一列代表相同类型的对象。感谢您的评论!

标签: wpf converter wpfdatagrid dataview


【解决方案1】:

这是使用DataView 作为您的 ItemsSource 的不幸副作用之一。在这种情况下,DataGridRow 的 DataContext 是 DataRowView,它具有属性 Row。此属性包含一个值数组,这些值是单个单元格。 DataGridCell 继承了 DataContext。然后,您要查找的第一列是Row[0],第二列是Row[1],依此类推。对DataGridTextColumn 使用下面的XAML,产生了您在我的测试中寻找的结果,我在绑定中使用Row[0] 而不是Make。并感谢您提供如此出色的工作代码,如此节省时间!

<DataGridTextColumn Binding="{Binding Row[0]}">
  <DataGridTextColumn.ElementStyle>
    <Style TargetType="{x:Type TextBlock}">
      <Setter Property="Background" Value="{Binding Row[0], Converter={StaticResource NameToBrushConverter}}"/>
    </Style>
  </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

我最近需要做一些类似的事情,我的输入必须是一个不确定维度的二维数组。我最终制作了一个可重用的自定义控件,扩展了 DataGrid。此控件管理自己的 DataContext(DataTable),这使得 UI 干净整洁,无需使用索引或任何代码隐藏。

可能有更好的方法来做到这一点,但我想不通。另外,这实际上取决于您要实现的目标。如果您的列在设计时已知,我会考虑创建一个包含对象的 ObservableCollection。如果没有,也许有人有更好的技巧,但至少这应该让你的代码正常工作。

【讨论】:

  • 嗯。您能否发布您的完整 XAML 和代码,我确实得到了一些颜色,但不是我所期望的。我会在我的原始图片中发布图片,但基本上我有 3 列(而不是预期的 2 列),并且第一列有颜色。您所做的唯一更改是在两个地方将“Make”更改为“Row[0]”吗?感谢收看!
  • 我一定会进一步研究。与此同时,您希望看到什么?需要注意的几件事:您需要在 DataGrid 上将“AutoGenerateColumns”设置为 false。您还需要像为“Make”列所做的那样在 XAML 中定义每一列。最后,您可以在 DataView 对象中设置列标题,使它们不是空白或“0”、“1”等。这应该为您提供一个起点。如果仍然需要,我会在今晚发布更多内容。
  • 尼克,我添加了一张非常粗略的图片,展示了我的预期。我宁愿不必定义每一列。这里有 2 个,但可能有 b 15 个。它们都完全相同。是不是有一些方法可以有一个模板或类似的?但是,如果有必要,我想我可以这样做。无论如何,任何想法都会受到赞赏。再说一次,我不喜欢使用 DataTable 或 DataView。这正是我提到的参考文献中使用的内容。谢谢!
  • 好的,我明白了。肯定有解决办法。我现在没有时间充实它,但我会在今天晚些时候。
  • 看起来你想通了?我可能会做类似的事情,不确定我可以在这里为您提供更多帮助,因为看起来您的想法是正确的,只是需要更多的肉!
【解决方案2】:

这是后代的解决方案。我并不声称它是最好的或最优雅的,并且会欢迎其他想法。特别是,必须公开 DataView 而不仅仅是 IEnumerable&lt;IEnumerable&lt;Column&gt;&gt; 的整个想法似乎很疯狂。

除了我最初提到的文章之外,我还发现以下内容非常有用:

https://codefornothing.wordpress.com/2009/01/25/the-wpf-datagrid-and-me/ https://social.msdn.microsoft.com/Forums/vstudio/en-US/b3cbe382-99b0-4005-8cb9-cd2f36e74ed3/how-to-change-a-datagrid-cells-background-color-using-a-converter?forum=wpf

代码

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        ViewModel vm = new ViewModel();

        List<Column> row1 = new List<Column>()
        {
            new Column(){Make = Make.Ford,OperatingStatus =  OperatingStatus.Broken},
            new Column(){Make = Make.Honda, OperatingStatus = OperatingStatus.Unknown}
        };
        List<Column> row2 = new List<Column>()
        {
            new Column() {Make = Make.GM, OperatingStatus = OperatingStatus.Working},
            new Column() {Make = Make.Toyota, OperatingStatus = OperatingStatus.Broken}
        };

        List<List<Column>> data = new List<List<Column>>();
        data.Add(row1);
        data.Add(row2);
        vm.Data = data;
        DataContext = vm;

    }
}

public enum OperatingStatus
{
    Working = 0,
    Broken = 1,
    Unknown = 2
}

public enum Make
{
    Ford,
    Honda,
    GM,
    Toyota
}

public class Column
{
    public Make Make { get; set; }
    public OperatingStatus OperatingStatus { get; set; }
}
public class ViewModel
{
    public IEnumerable<IEnumerable<Column>>  Data { get; set; }

    public DataView MyDataTable
    {
        get
        {
            var rows = Data.Count();
            var cols = Data.First().Count();
            var t = new DataTable();
            for (var c = 0; c < cols; c++)
            {
                t.Columns.Add(new DataColumn(c.ToString()));
                //t.Columns.Add(new DataColumn(c.ToString(),typeof(StackOverFlowDataGridQuestion.Column)));
            }

            foreach (var row in Data)
            {
                var newRow = t.NewRow();
                int c = 0;
                foreach (var col in row)
                {
                    newRow[c] = col.Make;
                    c++;
                }
                t.Rows.Add(newRow);
            }
            return t.DefaultView;
        }
    }
}



public class ConverterHoldoffGridColor : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values[1] is DataRow)
        {
            var cell = (DataGridCell) values[0];
            var row = (DataRow) values[1];
            var columnName = cell.Column.SortMemberPath;
            string input = (row[columnName] as string);
            //string input = (row[columnName] as StackOverFlowDataGridQuestion.Column).Make.ToString();

            switch (input)
            {
                case "Ford":
                    return Brushes.LightGreen;
                case "GM":
                    return Brushes.Red;
                case "Toyota":
                    return Brushes.Blue;
                case "Honda":
                    return Brushes.Yellow;
                default:
                    return DependencyProperty.UnsetValue;
            }
        }
        else
        {
            return SystemColors.AppWorkspaceColor;
        }
        
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

这里是 XAML

<Window x:Class="StackOverFlowDataGridQuestion.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:StackOverFlowDataGridQuestion"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Window.Resources>
    
    <local:ConverterHoldoffGridColor x:Key="bgHoldoffGridColor" />
    <Style x:Key="CellHighlighterStyle">

       
        <Setter Property="DataGridCell.Background">
            <Setter.Value>
                <MultiBinding
                Converter="{StaticResource bgHoldoffGridColor}" >
                    <MultiBinding.Bindings>
                        <Binding RelativeSource="{RelativeSource Self}"/>
                        <Binding Path="Row" Mode="OneWay"/>
                    </MultiBinding.Bindings>
                </MultiBinding>
            </Setter.Value>
        </Setter>

       
    </Style>
</Window.Resources>
<Grid>
    <ScrollViewer>
        <DataGrid x:Name="myDataGrid" CellStyle="{StaticResource CellHighlighterStyle}" 
            DataContext="{Binding }"                      
                  ItemsSource="{Binding MyDataTable}">

           
        </DataGrid>
        
    </ScrollViewer>
</Grid>

【讨论】:

    猜你喜欢
    • 2013-01-28
    • 2015-05-14
    • 2011-04-03
    • 2020-06-02
    • 2016-11-15
    • 2011-10-15
    • 2010-12-17
    • 1970-01-01
    • 2011-09-12
    相关资源
    最近更新 更多