WPF dataGrid查找单个单元格的X和Y并设置背景色 [英] WPF dataGrid Find Single Cell's X and Y and set background colour

查看:61
本文介绍了WPF dataGrid查找单个单元格的X和Y并设置背景色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个绑定到数据网格(MVVM)的类型化数据集。我也有一个点列表(类型化数据集中的X和Y),指出哪些单元格有错误。检测这种情况的逻辑很复杂,并且运行在服务器端。

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.

我的目标是在每个单元格有错误的情况下,将背景涂成不同的颜色(即点列表包含该单元格的X和Y。)

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).

dataGrid定义为:

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>

我相信我现在已经很接近了(经过很多测试和谷歌搜索才能到达这里)。填充所有内容后,当选择单元格时,我可以找到单元格的X和Y,即 SelectedCellsChanged方法。

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

因此,我创建了一个多值转换器来执行相同的操作。使用转换器时,如果单元格的列为空,则会出现问题,并且currentCell.Item(DataGridCellInfo).Item也将具有{DependencyProperty.UnsetValue}。

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?

谢谢

推荐答案

我如何解决我的问题,(不确定它是否是最佳选择,但到目前为止是否可行):

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:

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

这篇关于WPF dataGrid查找单个单元格的X和Y并设置背景色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆