WPF dataGrid Находит X и Y отдельной ячейки и устанавливает цвет фона - PullRequest
2 голосов
/ 14 апреля 2011

У меня есть типизированный набор данных, который связан с сетью данных (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>

Я полагаю, что сейчас близок к этому (много тестов и поиск в Google, чтобы добраться сюда). Я могу найти 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). Элемент будет иметь {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 Ответ

2 голосов
/ 26 апреля 2011

Вот как я решил свою проблему (не уверен, что она оптимальна, но, кажется, работает) (пока):

У меня есть многоканальный преобразователь в стиле для ячейки сетки данных:

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