我有一个绑定到数据网格(MVVM)的类型化数据集。我还有一个Point(列表数据集中的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>
我相信我现在接近它(经过大量测试和谷歌搜索到此处)。在填充所有内容后更改单元格选项时,我可以找到Cell的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;
}
所以我创建了一个多值转换器来做同样的事情。当使用转换器时Cell的Column为null,以及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;
}
}
这是因为绑定/创建顺序吗?有办法解决这个问题吗?
由于
答案 0 :(得分:2)
这就是我解决问题的方法,(不确定它是否最佳,但似乎有效,(到目前为止):
我在数据网格单元格的样式上有一个多值转换器:
<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>
转换器:
public class DataGridCellOnErrorConversion : IMultiValueConverter
{
private readonly SolidColorBrush DefaultColour = new SolidColorBrush(Colors.White);
private readonly SolidColorBrush ErrorColour = new SolidColorBrush(Colors.Red);
private readonly SolidColorBrush AlternatingColour = new SolidColorBrush(Colors.AliceBlue);
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 = -1;
ItemCollection itemCollection = grid.Items;
for (int i = 0; i < itemCollection.Count; i++)
{
if (itemCollection.CurrentItem == itemCollection[i])
y = i;
}
x = dgc.Column.DisplayIndex;
DataRowView currentRowView = null;
FieldInfo fi = dgc.GetType().GetField("_owner", BindingFlags.NonPublic | BindingFlags.Instance);
try
{
if (fi != null)
{
DataGridRow dataGridRow = fi.GetValue(dgc) as DataGridRow;
if(dataGridRow != null)
currentRowView = dataGridRow.Item as DataRowView;
}
}
catch (InvalidCastException) { }
if(currentRowView != null)
{
for (int i = 0; i < itemCollection.Count; i++)
{
if (currentRowView == itemCollection[i])
y = i;
}
}
if (problems.Any(problem => System.Convert.ToInt32(problem.X) == x && System.Convert.ToInt32(problem.Y) == y))
{
return ErrorColour;
}
return y % 2 == 0 ? AlternatingColour : DefaultColour;
}
}