我使用以下链接在表格中显示我的二维数据:
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;在两个地方,我得到了以下,这是进步,因为有一些颜色!如果有更多更改,我会在此处报告。
我原本希望福特广场是绿色,本田是黄色,通用汽车是红色,丰田是蓝色。更像下面的东西(请原谅我糟糕的标记技巧)。
答案 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>