WPF dataGrid查找单个单元格的X和Y并设置背景颜色

时间:2011-04-14 15:05:34

标签: wpf wpfdatagrid

我有一个绑定到数据网格(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;
    }  
}

这是因为绑定/创建顺序吗?有办法解决这个问题吗?

由于

1 个答案:

答案 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;
    }
}