WPF dataGrid查找单个单元格的X和Y并设置背景颜色
我有一个绑定到数据网格(MVVM)的类型化数据集。我还有一个点列表(类型数据集中的 X 和 Y),表明哪些单元格有错误。检测这一点的逻辑很复杂并且在服务器端运行。
我的目标是如果每个单元格有错误,则将其背景绘制为不同的颜色(即点列表包含该单元格的 X 和 Y)。
dataGrid 的定义是:
<DataGrid x:Name="gridData" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
BorderThickness="0 0 0 0" Margin="0 0 0 0" AutoGenerateColumns="True" AlternationCount="1" AlternatingRowBackground="AliceBlue"
ItemsSource="{Binding Path=EquisDataTable}" SelectionUnit="Cell" SelectedCellsChanged="gridData_SelectedCellsChanged"
AutoGeneratedColumns="GridData_OnAutoGeneratedColumns" AutoGeneratingColumn="gridData_AutoGeneratingColumn" Height="350">
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Setters>
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource onErrorConverter}">
<Binding RelativeSource="{RelativeSource Self}" />
<Binding RelativeSource="{RelativeSource AncestorType=SampleTests:SampleTestUserControlBase}" Path="DataContext.Problems" />
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</DataGrid.CellStyle>
</DataGrid>
我相信我现在已经接近它了(经过大量测试和谷歌搜索才到达这里)。当填充所有内容后更改单元格选择时,我可以找到单元格的 X 和 Y,“SelectedCellsChanged”方法。这并不能让我到达每个单元格并在加载时检查其值。
private void gridData_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
int x;
int y;
if (TryGetDataGridCellXandY(gridData.CurrentCell, gridData, out x, out y))
{ }
}
private bool TryGetDataGridCellXandY(DataGridCellInfo dgc, DataGrid dataGrid, out int x, out int y)
{
int columnIndex = dgc.Column.DisplayIndex;
return TryGetDataGridCellXandY(columnIndex, dataGrid, out x, out y);
}
private bool TryGetDataGridCellXandY(int columnIndex, DataGrid dataGrid, out int x, out int y)
{
DataGridCellInfo currentCell = dataGrid.CurrentCell;
int rowIndex = int.MinValue;
DataRowView rowView = currentCell.Item as DataRowView;
if (rowView != null)
{
DataRow dataRow = rowView.Row;
FieldInfo fi = typeof(DataRow).GetField("_rowID", BindingFlags.NonPublic | BindingFlags.Instance);
try
{
if (fi != null)
{
rowIndex = System.Convert.ToInt32(fi.GetValue(dataRow));
}
}
catch (InvalidCastException) { }
}
x = columnIndex;
y = rowIndex;
return x > 0 && y > 0;
}
所以我创建了一个多值转换器来完成同样的事情。使用转换器时,当单元格的列为空时,就会出现问题,并且 currentCell.Item (DataGridCellInfo).Item 将具有 {DependencyProperty.UnsetValue}。
public class DataGridCellOnErrorConversion : IMultiValueConverter
{
private const string DefaultColour = "White";
private const string ErrorColour = "Red";
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length != 3)
return DefaultColour;
DataGridCell dgc = values[0] as DataGridCell;
if(dgc == null)
return DefaultColour;
IList<Point> problems = values[1] as IList<Point>;
if(problems == null)
return DefaultColour;
DataGrid grid = values[2] as DataGrid;
if (grid == null)
return DefaultColour;
int x;
int y;
if (TryGetDataGridCellXandY(grid.CurrentCell, grid, out x, out y))
{
if (problems.Any(problem => System.Convert.ToInt32(problem.X) == x && System.Convert.ToInt32(problem.Y) == y))
{
return ErrorColour;
}
}
return DefaultColour;
}
private bool TryGetDataGridCellXandY(DataGridCellInfo dgc, DataGrid dataGrid, out int x, out int y)
{
int columnIndex = dgc.Column.DisplayIndex;
return TryGetDataGridCellXandY(columnIndex, dataGrid, out x, out y);
}
private bool TryGetDataGridCellXandY(int columnIndex, DataGrid dataGrid, out int x, out int y)
{
DataGridCellInfo currentCell = dataGrid.CurrentCell;
int rowIndex = int.MinValue;
DataRowView rowView = currentCell.Item as DataRowView;
if (rowView != null)
{
DataRow dataRow = rowView.Row;
FieldInfo fi = typeof(DataRow).GetField("_rowID", BindingFlags.NonPublic | BindingFlags.Instance);
try
{
if (fi != null)
{
rowIndex = System.Convert.ToInt32(fi.GetValue(dataRow));
}
}
catch (InvalidCastException) { }
}
x = columnIndex;
y = rowIndex;
return x > 0 && y > 0;
}
}
这是因为绑定/创建顺序吗?有办法解决这个问题吗?
谢谢
I have a typed dataset that is being bound to a datagrid (MVVM). I also have a list of Points (X and Y in the typed dataset) that say which cells have errors. The logic to detect this is complex and is run on the server end.
My goal is to paint each cell's background a different colour if they have an error, (i.e. the list of points contains that Cell's X and Y).
The dataGrid is defined as:
<DataGrid x:Name="gridData" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
BorderThickness="0 0 0 0" Margin="0 0 0 0" AutoGenerateColumns="True" AlternationCount="1" AlternatingRowBackground="AliceBlue"
ItemsSource="{Binding Path=EquisDataTable}" SelectionUnit="Cell" SelectedCellsChanged="gridData_SelectedCellsChanged"
AutoGeneratedColumns="GridData_OnAutoGeneratedColumns" AutoGeneratingColumn="gridData_AutoGeneratingColumn" Height="350">
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Setters>
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource onErrorConverter}">
<Binding RelativeSource="{RelativeSource Self}" />
<Binding RelativeSource="{RelativeSource AncestorType=SampleTests:SampleTestUserControlBase}" Path="DataContext.Problems" />
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</DataGrid.CellStyle>
</DataGrid>
I believe I am close to it now (taken a lot of testing and Googling to get here). I can find a Cell's X and Y when a cell selection is changed after everything has been populated, "SelectedCellsChanged" method. This does not let me get to every cell and check its value though on load.
private void gridData_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
int x;
int y;
if (TryGetDataGridCellXandY(gridData.CurrentCell, gridData, out x, out y))
{ }
}
private bool TryGetDataGridCellXandY(DataGridCellInfo dgc, DataGrid dataGrid, out int x, out int y)
{
int columnIndex = dgc.Column.DisplayIndex;
return TryGetDataGridCellXandY(columnIndex, dataGrid, out x, out y);
}
private bool TryGetDataGridCellXandY(int columnIndex, DataGrid dataGrid, out int x, out int y)
{
DataGridCellInfo currentCell = dataGrid.CurrentCell;
int rowIndex = int.MinValue;
DataRowView rowView = currentCell.Item as DataRowView;
if (rowView != null)
{
DataRow dataRow = rowView.Row;
FieldInfo fi = typeof(DataRow).GetField("_rowID", BindingFlags.NonPublic | BindingFlags.Instance);
try
{
if (fi != null)
{
rowIndex = System.Convert.ToInt32(fi.GetValue(dataRow));
}
}
catch (InvalidCastException) { }
}
x = columnIndex;
y = rowIndex;
return x > 0 && y > 0;
}
So I created a multi value converter to do the same thing. The problem arises when a Cell's Column is null when using the converter, also the currentCell.Item (DataGridCellInfo).Item will have {DependencyProperty.UnsetValue}.
public class DataGridCellOnErrorConversion : IMultiValueConverter
{
private const string DefaultColour = "White";
private const string ErrorColour = "Red";
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length != 3)
return DefaultColour;
DataGridCell dgc = values[0] as DataGridCell;
if(dgc == null)
return DefaultColour;
IList<Point> problems = values[1] as IList<Point>;
if(problems == null)
return DefaultColour;
DataGrid grid = values[2] as DataGrid;
if (grid == null)
return DefaultColour;
int x;
int y;
if (TryGetDataGridCellXandY(grid.CurrentCell, grid, out x, out y))
{
if (problems.Any(problem => System.Convert.ToInt32(problem.X) == x && System.Convert.ToInt32(problem.Y) == y))
{
return ErrorColour;
}
}
return DefaultColour;
}
private bool TryGetDataGridCellXandY(DataGridCellInfo dgc, DataGrid dataGrid, out int x, out int y)
{
int columnIndex = dgc.Column.DisplayIndex;
return TryGetDataGridCellXandY(columnIndex, dataGrid, out x, out y);
}
private bool TryGetDataGridCellXandY(int columnIndex, DataGrid dataGrid, out int x, out int y)
{
DataGridCellInfo currentCell = dataGrid.CurrentCell;
int rowIndex = int.MinValue;
DataRowView rowView = currentCell.Item as DataRowView;
if (rowView != null)
{
DataRow dataRow = rowView.Row;
FieldInfo fi = typeof(DataRow).GetField("_rowID", BindingFlags.NonPublic | BindingFlags.Instance);
try
{
if (fi != null)
{
rowIndex = System.Convert.ToInt32(fi.GetValue(dataRow));
}
}
catch (InvalidCastException) { }
}
x = columnIndex;
y = rowIndex;
return x > 0 && y > 0;
}
}
Is this because of a binding / creation order? Is there a way around this?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这就是我解决问题的方法,(不确定它是否是最佳的,但似乎有效,(到目前为止):
我在数据网格单元格的样式上有一个多值转换器:
并且转换器:
This is how I solved my problem, (not sure if it is optimal but seems to work, (so far):
I have a multi value converter on the Style for the datagrid cell:
And the converter: