Как динамически обновить стили ячеек?

Никак не получается динамически поменять цвет определённого моим интерфейсом столбца. Смена стиля ячеек срабатывает только если строить таблицу с нуля каждый раз при изменении данных, но тогда это очень тормозит интерфейс. А если менять только содержание ячеек, то триггер стиля уже не срабатывает. Ситуация осложняется тем, что колонки должны генериться автоматически.

Существенные для вопроса фрагменты кода:

public DataTable? DataTable { get; set; } = null;

private void CreateDataTable()
{
    var dt = DataTable;
    if (dt == null)
    {
        dt = new("Заголовок");
        dt.BeginInit();
        dt.Columns.Add("Первая колонка", typeof(MyTableCell));
        foreach (var col in GetColumns())
        {
            dt.Columns.Add(col, typeof(MyTableCell));
        }
        foreach (var item in GetLeftHeaderData())
        {
            var newRow = dt.NewRow();
            newRow[0] = new MyTableCell() { Value = item, Precision = 2 };
            var i = 1;
            // Делаем заготовку - ячейки с нулями 
            foreach (var col in GetColumns())
            {
                newRow[i] = new MyTableCell() { Value = 0, Precision = 3 }; ;
                i++;
            }
            dt.Rows.Add(newRow);
            dt.EndInit();
        }
        DataTable = dt;
    }
    dt.BeginLoadData();
    var x = 0;
    foreach (var col in GetColumns())
    {
        x++;
        var y = 0;
        if (col.Equals(SelectedColumn))
        {
            foreach (var vol in GetValues())
            {
                var cell = (MyTableCell)dt.Rows[y][x];
                cell.Value = vol;
                cell.IsActive = true;
                dt.Rows[y][x] = cell;
                var c = dt.Rows[y][x];
                y++;
            }
        }
        else
        {
            foreach (var item in GetData(col))
            {
                var cell = (MyTableCell)dt.Rows[y][x];
                cell.Value = item;
                cell.IsActive = false;
                dt.Rows[y][x] = cell;
                y++;
            }
        }
    }
    dt.EndLoadData();
    OnPropertyChanged(nameof(DataTable));
}

Используемый для ячеек класс:

    public class MyTableCell
    {
        /// <summary>
        /// Активная колонка
        /// </summary>
        public bool IsActive { get; set; } = false;

        /// <summary>
        /// Значение
        /// </summary>
        public float Value { get; set; }

        /// <summary>
        /// Число отображаемых знаков после запятой
        /// </summary>
        public int Precision { get; set; } = 3;

        public string Display => Value.ToString($"f{Precision}");

        public override string ToString()
        {
            return Display;
        }
    }

Кусок XAML:

<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
    <Grid.Resources>
        <conv:RowIndexConverter x:Key="RowIndexConverter"/>
        <conv:ColumnConverter x:Key="ColumnConverter"/>
    </Grid.Resources>
    <DataGrid Name="TableData"
          AutoGenerateColumns="True" 
          ItemsSource="{Binding DataTable, NotifyOnTargetUpdated=True}"
          IsReadOnly="True"
          CanUserReorderColumns="False"
          CanUserSortColumns="False">
        <DataGrid.Resources>
            <Style BasedOn="{StaticResource {x:Type DataGridColumnHeader}}" TargetType="{x:Type DataGridColumnHeader}" >
                <Setter Property="Background" Value="LightGray" />
                <Setter Property="Foreground" Value="Black" />
                <Setter Property="BorderBrush" Value="Black"/>
                <Setter Property="FontWeight" Value="Bold"/>
                <Setter Property="BorderThickness" Value="1 1 1 1"/>
                <Setter Property="Margin" Value="-1,-1,0,0" />
                <Setter Property="Height" Value="auto" />
                <Setter Property="Width" Value="auto"/>
                <Setter Property="HorizontalContentAlignment" Value="Center"/>
                <Setter Property="ContentStringFormat" Value="{}{0:#.###}"/>
            </Style>
        </DataGrid.Resources>
        <DataGrid.CellStyle>
            <Style TargetType="DataGridCell">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Column.DisplayIndex}" Value="0">
                        <Setter Property="Background" Value="LightGray"/>
                    </DataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition  Binding="{Binding RelativeSource={RelativeSource Self}, Path=Column.DisplayIndex}" Value="0"/>
                            <Condition  Binding="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Converter={StaticResource RowIndexConverter}}" Value="10"/>
                        </MultiDataTrigger.Conditions>
                        <Setter Property="FontWeight" Value="Bold"/>
                    </MultiDataTrigger>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource ColumnConverter}}" Value="True">
                        <Setter Property="Background" Value="Aquamarine"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </DataGrid.CellStyle>
    </DataGrid>
</Grid>

Конвертеры тоже могу привести, но проблема не в них. Последний триггер не работает при изменении значений в таблице и даже триггер вообще не дёргается. Данные меняются и показываются изменёнными, всё прекрасно, но в триггер управление не попадает. Может можно как-то заставить дата грид пересчитать стили "вручную" хотя бы? Рефреш какой-то может есть или что-то такое?

Допускаю, что я вообще неправильно работаю с DataTable, но хотелось бы просто уже применить нормально стиль к столбцу и закончить эту задачу.

Да, и ещё мне непонятно, почему хотя я кидаю в ячейки определённый объект, но он всё-равно не видится в ячейках как объект и показывается фактически только через ToString в итоге. Но это не главный вопрос.

P.S. Код слегка исправлен для выкладки, не обращайте внимание на всякие GetColumns и прочее такое, там в рабочем коде несколько другое, я мог ошибиться в этих местах, когда выкладывал код сюда.


Ответы (1 шт):

Автор решения: DmitriySidyakin
  1. Вот отвеченный аналогичный вопрос из США: https://stackoverflow.com/questions/60286718/change-wpf-datagrid-column-cell-background-color-based-on-values для перевода можно использовать: translate.google.com (первую ссылку в форму второй ссылки и получите перевод ответа).

  2. Вот пример моего проекта при пересовке контролов полнностью на форме в виде svg-изображений. Минимальное приложение без большого стека не тормозят и не подвисает. Возможно придётся разделить на 2 (и более исполняемых файла и закрывать их). Пишите пока не затормозит), вот пример одна формочка не тормозит. Просмотреть можно если интересно, если в будующем Вам в приложении потребуется строить графики (как рисовать svg) - https://github.com/DmitriySidyakin/Chess . Ответ на Ваш вопрос вы возможно ещё поняли прочитав все коментарии. Когда закончите править код, пожалуйста дайте ответ самостоятельно. Не оставляйте вопросы пустыми. Защитайте ответ себе, когда воспроизведёте ответ. Будет проще гуглить в рунете! Если у Вас есть время и вы патриот своей профессии!

Но используйте пунк 1. У Вас аналогичный код. Пунк 2 для ознакомления с более динамически генерируемыми контролами. Там в форму просто вставляется xml wpf.

→ Ссылка