Проблема объединения ячеек при генерации таблицы в приложении WPF с использованием бибилотеки Syncfusion

Проблема заключается в том что я генерирую таблицу используя данные из БД. Далее приложу скрины как должно быть и как получается на самом деле.

как должно быть: как должно быть

а вот как у меня получается:

мой результат

проблема в поле с названием класса, оно не хочет групировать всё поле в одну строку. Я пытался делать и селектор, и через событие но не работает. Взможно гте-то неправильный порядок действий, но не понятно где. Я уже и делал логгирование через консоль. Вроде правлильно определяет в каком поле надо выполнить объединение, и выводит что объединение отработало, но по факту ничего не происходит. Сижу уже 3 дня не могу понять, ниже сккину весь код который этим занимается. класс занимающийся отображением данных и событие на объединение ячеек:

{
    public CollectionViewSource AccountsViewSource { get; set; }
    public SfDataGrid DataGrid { get; set; }

    // Конструктор для DisplayDataService
    public DisplayDataService(int fileId, SfDataGrid dataGrid)
    {
        AccountsViewSource = new CollectionViewSource();
        DataGrid = dataGrid;
        LoadDataFromDatabase(fileId);
    }

    // Загрузка данных из базы данных и заполнение SfDataGrid
    private void LoadDataFromDatabase(int fileId)
    {
        using (var context = new AppDbContext())
        {
            Console.WriteLine("Создание контекста базы данных...");

            // Получение информации о файле из базы данных
            var fileInDb = context.Files.FirstOrDefault(f => f.Id == fileId);

            // Получение данных по счетам с соответствующими связанными сущностями из базы данных
            var accounts = context.Accounts
                .Include(a => a.AccountDetails)
                .Include(a => a.Class)
                .Include(a => a.AccountGroups)
                .Where(a => a.Class.FileId == fileId)
                .ToList();

            // Преобразование данных по счетам в модели отображения
            var accountDisplayModels = accounts.Select(account => new AccountDisplayModel
            {
                // Отображение свойств счета на свойства модели отображения
                AccountNumber = account.AccountNumber,
                ClassName = account.Class.ClassName,
                AccountGroup = account.AccountGroups.AccountGroup,
                ActiveOpeningBalance = account.AccountDetails.ActiveOpeningBalance,
                PassiveOpeningBalance = account.AccountDetails.PassiveOpeningBalance,
                DebitTurnover = account.AccountDetails.DebitTurnover,
                LoanTurnover = account.AccountDetails.LoanTurnover,
                ActiveClosingBalance = account.AccountDetails.ActiveClosingBalance,
                PassiveClosingBalance = account.AccountDetails.PassiveClosingBalance,
                IsGroupSummary = false,
                IsClassSummary = false,
                DisplayText = account.AccountNumber.ToString(),

                // Дополнительные свойства
                // ...
            }).ToList();

            var displayData = new List<AccountDisplayModel>();

            // Группировка и суммирование моделей отображения счетов
            foreach (var classGroup in accountDisplayModels.GroupBy(a => a.ClassName).OrderBy(g => g.Key))
            {
                // Добавление заголовка класса
                displayData.Add(new AccountDisplayModel { DisplayText = classGroup.Key, IsClassHeader = true });

                // Перебор групп счетов внутри класса
                foreach (var group in classGroup.GroupBy(a => a.AccountGroup).OrderBy(g => g.Key))
                {
                    // Добавление отдельных счетов
                    displayData.AddRange(group.OrderBy(a => a.AccountNumber));

                    // Добавление суммарной информации по группе счетов
                    var groupSummary = new AccountDisplayModel
                    {
                        // Заполнение свойств суммарной информации по группе
                        DisplayText = $"{group.Key}",
                        ActiveOpeningBalance = group.Sum(a => a.ActiveOpeningBalance),
                        PassiveOpeningBalance = group.Sum(a => a.PassiveOpeningBalance),
                        DebitTurnover = group.Sum(a => a.DebitTurnover),
                        LoanTurnover = group.Sum(a => a.LoanTurnover),
                        ActiveClosingBalance = group.Sum(a => a.ActiveClosingBalance),
                        PassiveClosingBalance = group.Sum(a => a.PassiveClosingBalance),
                        IsGroupSummary = true,

                        // Дополнительные свойства
                        // ...
                    };

                    displayData.Add(groupSummary);
                }

                // Добавление суммарной информации по классу
                var classSummary = new AccountDisplayModel
                {
                    // Заполнение свойств суммарной информации по классу
                    DisplayText = "ПО КЛАССУ",
                    ActiveOpeningBalance = classGroup.Sum(a => a.ActiveOpeningBalance),
                    PassiveOpeningBalance = classGroup.Sum(a => a.PassiveOpeningBalance),
                    DebitTurnover = classGroup.Sum(a => a.DebitTurnover),
                    LoanTurnover = classGroup.Sum(a => a.LoanTurnover),
                    ActiveClosingBalance = classGroup.Sum(a => a.ActiveClosingBalance),
                    PassiveClosingBalance = classGroup.Sum(a => a.PassiveClosingBalance),
                    IsClassSummary = true,

                    // Дополнительные свойства
                    // ...
                };

                displayData.Add(classSummary);
            }

            // Подписка на событие QueryCoveredRange для настройки обработки
            DataGrid.QueryCoveredRange += sfDataGrid_QueryCoveredRange;

            // Установка данных отображения в качестве источника для CollectionViewSource
            AccountsViewSource.Source = displayData;
        }
    }

    // Настройка обработки события QueryCoveredRange в SfDataGrid
    private void sfDataGrid_QueryCoveredRange(object sender, GridQueryCoveredRangeEventArgs e)
    {
        var dataGrid = sender as SfDataGrid;

        if (dataGrid == null)
        {
            Console.WriteLine("SfDataGrid не найден.");
            return;
        }

        var recordIndex = dataGrid.ResolveToRecordIndex(e.RowColumnIndex.RowIndex);

        if (recordIndex < 0)
        {
            Console.WriteLine($"Не удалось разрешить индекс записи для строки: {e.RowColumnIndex.RowIndex}");
            return;
        }

        var record = dataGrid.View.Records[recordIndex].Data as AccountDisplayModel;

        if (record != null)
        {
            // Проверка, является ли запись заголовком класса
            if (record.DisplayText != null && (record.DisplayText.StartsWith("КЛАСС") || record.IsClassHeader))
            {
                // Покрытие всей строки для заголовка класса
                int startColumnIndex = 1;
                int endColumnIndex = dataGrid.Columns.Count;

                e.Range = new CoveredCellInfo(e.RowColumnIndex.RowIndex, startColumnIndex, e.RowColumnIndex.RowIndex, endColumnIndex);
                e.Handled = true;
            }
            else
            {
                // Обработка других случаев при необходимости
                Console.WriteLine();
            }
        }
        else
        {
            Console.WriteLine();
        }
    }

} 

селектор, который определяет какие ячейки обыные, а какие необходимо объеденять и к каким применить слити:

public class ClassHeaderTemplateSelector : DataTemplateSelector
{
    // Шаблон для заголовка класса
    public DataTemplate ClassHeaderTemplate { get; set; }

    // Обычный шаблон для отображения данных
    public DataTemplate NormalTemplate { get; set; }

    // Переопределение метода выбора шаблона для элемента
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        // Преобразование объекта в модель отображения счета
        var record = item as AccountDisplayModel;

        // Проверка, является ли элемент заголовком класса
        if (record != null && record.IsClassHeader)
        {
            // Возврат шаблона для заголовка класса
            return ClassHeaderTemplate;
        }
        else
        {
            // Возврат обычного шаблона для отображения данных
            return NormalTemplate;
        }
    }
} 

модель данных для генерации таблицы:

public class AccountDisplayModel
{
    public int AccountNumber { get; set; }
    public int AccountGroup { get; set; }
    public string ClassName { get; set; }
    public decimal ActiveOpeningBalance { get; set; }
    public decimal PassiveOpeningBalance { get; set; }
    public decimal DebitTurnover { get; set; }
    public decimal LoanTurnover { get; set; }
    public decimal ActiveClosingBalance { get; set; }
    public decimal PassiveClosingBalance { get; set; }
    public bool IsGroupSummary { get; set; }
    public bool IsClassSummary { get; set; }
    public bool IsClassHeader { get; set; }
    public string DisplayText { get; set; }
}

XAML код этого окна:

 <Window.Resources>
    <DataTemplate x:Key="ClassHeaderCellTemplate">
        <TextBlock Text="{Binding DisplayText}" 
               HorizontalAlignment="Center" 
               VerticalAlignment="Center" 
               Background="LightGray" />
    </DataTemplate>

    <DataTemplate x:Key="NormalCellTemplate">
        <TextBlock Text="{Binding DisplayText}" />
    </DataTemplate>

    <local1:ClassHeaderTemplateSelector x:Key="classHeaderTemplateSelector"
                                   ClassHeaderTemplate="{StaticResource ClassHeaderCellTemplate}" 
                                   NormalTemplate="{StaticResource NormalCellTemplate}" />
</Window.Resources>
<Grid>
    <syncfusion:SfDataGrid x:Name="sfDataGrid"
                   AutoGenerateColumns="False"
                   ItemsSource="{Binding AccountsViewSource.View}"
                   SelectionUnit="Cell"
                   NavigationMode="Cell"
                   AllowEditing="False"
                   AllowDeleting="False"
                   AllowDraggingColumns="False"
                   AllowResizingColumns="True"
                   AllowSorting="True"
                   ShowGroupDropArea="False">
        <syncfusion:SfDataGrid.StackedHeaderRows>
            <syncfusion:StackedHeaderRow>
                <syncfusion:StackedHeaderRow.StackedColumns>
                    <syncfusion:StackedColumn ChildColumns="ActiveOpeningBalance,PassiveOpeningBalance" HeaderText="ВХОДЯЩЕЕ САЛЬДО"/>
                    <syncfusion:StackedColumn ChildColumns="DebitTurnover,LoanTurnover" HeaderText="ОБОРОТЫ"/>
                    <syncfusion:StackedColumn ChildColumns="ActiveClosingBalance,PassiveClosingBalance" HeaderText="ИСХОДЯЩЕЕ САЛЬДО"/>
                </syncfusion:StackedHeaderRow.StackedColumns>
            </syncfusion:StackedHeaderRow>
        </syncfusion:SfDataGrid.StackedHeaderRows>
        <syncfusion:SfDataGrid.Columns>
            <syncfusion:GridTemplateColumn MappingName="DisplayText" HeaderText="Б/сч" 
                                       CellTemplateSelector="{StaticResource classHeaderTemplateSelector}"/>
            <syncfusion:GridTextColumn MappingName="ActiveOpeningBalance" HeaderText="Актив"/>
            <syncfusion:GridTextColumn MappingName="PassiveOpeningBalance" HeaderText="Пассив"/>
            <syncfusion:GridTextColumn MappingName="DebitTurnover" HeaderText="Дебет"/>
            <syncfusion:GridTextColumn MappingName="LoanTurnover" HeaderText="Кредит"/>
            <syncfusion:GridTextColumn MappingName="ActiveClosingBalance" HeaderText="Актив"/>
            <syncfusion:GridTextColumn MappingName="PassiveClosingBalance" HeaderText="Пассив"/>
        </syncfusion:SfDataGrid.Columns>
    </syncfusion:SfDataGrid>
</Grid>

конфигурация окна:

 public partial class DataDisplayWindow : Window
{
    public DataDisplayWindow(int fileId)
    {
        InitializeComponent();
        DataContext = new DisplayDataService(fileId, sfDataGrid);
    }
}

в общем вот, весь код скинул. Не могу понять в чем проблема, сам я не эксперт в WPF приложениях так еще и с библиотекой. Если вы знаете как это сделать без использования библиотеки буду так же рад, но вот пришлось это делать


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