我有一个问题3天都无法处理。听起来很简单,但事实上却复杂得多。我有一个应用程序,它从 Excel 文件中获取数据并将其存储在数据库中,然后该应用程序使用这些数据形成自己的表。一切都会好起来的,但是表中的一个字段无法管理。结构本身如下:4 个主柱。第一列存储帐号、账户组以及一组账户的总金额、类别以及按类别划分的账户组的总金额。所有字段均已正确排列,除了带有类名称的一个字段外,它应该合并所有列。接下来,我将附上应该如何以及实际如何的屏幕截图。
接下来,我将提供我尝试执行此操作的代码,我会立即说,我是新手开发人员,不要严格判断:
{
public CollectionViewSource AccountsViewSource { get; set; }
public SfDataGrid DataGrid { get; set; }
public DisplayDataService(int fileId, SfDataGrid dataGrid)
{
AccountsViewSource = new CollectionViewSource();
DataGrid = dataGrid;
LoadDataFromDatabase(fileId);
}
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);
}
DataGrid.QueryCoveredRange += sfDataGrid_QueryCoveredRange;
AccountsViewSource.Source = displayData;
}
}
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 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; }
}
窗口生成:
{
public DataDisplayWindow(int fileId)
{
InitializeComponent();
DataContext = new DisplayDataService(fileId, sfDataGrid);
}
}
XAML代码:
<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 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;
}
}
}
该应用程序使用以下库:EF core、Plus、Syncfusion.Grid.WPF
当一个对象具有 Is Class Header = true 属性时,则该对象的字段的所有单元格应合并为一个。但是具有 Is Class Header = true 属性的这种类型的对象分别仅存储在 1 列中,此类对象的第一列应该是整个表格宽度的一列,如屏幕截图所示
我已经尝试了很多选项,对每行代码使用日志记录、调试以及更新可视化组件的不同方法......没有任何帮助。
根据报告的场景,结合上述代码片段,发现CoveredCellInfo中sfDatagrid_QueryCoveredRange方法的参数解析存在一些错位。
请注意,CoveredCellInfo 的解析参数应包含四个参数。前两个参数(left 和 right)应考虑列值(startcolumnindex 和 endcolumnindex),而其他两个参数(top 和bottom)应考虑行值(startrowindex 和 endrowindex)。根据这些参数,可以合并单元格。
请参阅随附的测试样品。请看一下这个。
请查找下面附加的 UG 链接以供参考处理“合并单元格”。