在DataGrid WPF中更改单元格的背景颜色

时间:2018-04-17 00:41:09

标签: wpf converter wpfdatagrid dataview

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

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&#39;与&#39; Row [0]&#39;在两个地方,我得到了以下,这是进步,因为有一些颜色!如果有更多更改,我会在此处报告。

enter image description here

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

enter image description here

2 个答案:

答案 0 :(得分:1)

这是使用DataView作为ItemsSource的不幸副作用之一。在这种情况下,DataGridRow的DataContext是DataRowView,其属性为Row。此属性包含一组值,这些值是单个单元格。 DataGridCell继承了DataContext。然后,您要查找的是第一列的Row[0],第二列的Row[1],依此类推。使用下面的XAML获取DataGridTextColumn,生成了我在测试中查找的结果,我在绑定中使用了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。如果没有,也许有人有更好的技巧,但至少这应该让你的代码工作。

答案 1 :(得分:0)

这是后人的解决方案。我并不认为它是最好的或最优雅的,并欢迎其他想法。特别是,必须公开DataView而不仅仅是IEnumberable的整个想法&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

CODE

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>