我正在尝试通过
DataGrid
绑定在 WPF DataTable
中显示 3 维数据。由于 DataGrid
只有行和列(2D),我的想法是对单元格进行模板化,以便它们托管 ListView
(或其他一些控件),并显示垂直堆叠的第三维值。
想要的结果是这样的:
这是一个带有模拟数据的高度简化但可重现的代码,我尝试创建这样一个
DataTable
:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel vm = new();
MyDataGrid.DataContext = vm.Table.DefaultView;
MyDataGrid.IsReadOnly = true;
}
public class ViewModel
{
public DataTable Table { get; init; }
public ViewModel()
{
Table = new DataTable();
Table.Columns.Add(" ");
Table.Columns.Add("c1");
Table.Columns.Add("c2");
Table.Columns.Add("c3");
for (int i = 1; i <= 3; i++ )
{
DataRow row = Table.NewRow();
row[0] = new List<object>() { "r" + i } ;
row[1] = new List<object>() { 10 * i, 20 * i, 25 * i } ;
row[2] = new List<object>() { 12 * i, 26 * i, 30 * i } ;
row[3] = new List<object>() { 16 * i, 28 * i, 36 * i };
Table.Rows.Add(row);
}
}
}
}
如您所见,我将 List 分配给每个单元格,想法是这创建了第三个维度,在单个单元格中存储多个值。
问题是,我不知道如何在 WPF 标记中对 DataGrid 进行模板化,以便正确解包并显示第三个维度,就像我上面显示的图像一样。我试过这个:
<DataGrid x:Name="MyDataGrid" ItemsSource="{Binding}">
<DataGrid.Resources>
<DataTemplate x:Key="DataGridTemplate">
<ListView ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</DataGrid.Resources>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="ContentTemplate" Value="{StaticResource DataGridTemplate}"/>
</Style>
</DataGrid.CellStyle>
</DataGrid>
但是当我编译并运行它时,
DataGrid
只显示空单元格,即使没有绑定错误。如果我不使用任何模板,单元格将显示 System.Data.DataRowView System.Collections.Generic.List
1[System.Object]`。
如果有人可以看一下(我上面提供的代码是完全可重现的示例),并让我知道如何创建正确的模板,我将非常感激?或者,如果我以错误的方式处理这个问题,我也愿意接受其他建议。
您的代码存在一些问题。
Type
问题 1 是您的列未键入,这似乎导致
DataRow["c1"]
等显示为 string
类型的 System.Collections.Generic.List1[System.Int32]
值,而不是集合本身。请参阅下面的调试器屏幕截图:
您将需要更新这些列并添加如下所示的类型(请注意,我还命名了第一列,以便我们可以引用它)。
Table.Columns.Add("c0");
Table.Columns.Add("c1", typeof(IList));
Table.Columns.Add("c2", typeof(IList));
Table.Columns.Add("c3", typeof(IList));
DataGridTemplateColumn
构建复杂的列第二个挑战是我认为您无法通过自动生成的列来完成您想要的任务。如果我将您的
CellTemplate
更改为仅绑定到 TextBlock
,您可以看到这些单元格的数据上下文实际上是整个 DataRowView
对象,而不仅仅是绑定的列:
<DataGrid.Resources>
<DataTemplate x:Key="DataGridTemplate">
<TextBlock Text="{Binding}" />
</DataTemplate>
</DataGrid.Resources>
更新您的
DataGrid
,如下所示,我能够生成我认为您正在寻找的内容。
<DataGrid x:Name="MyDataGrid"
ItemsSource="{Binding}"
AutoGenerateColumns="False">
<DataGrid.Resources>
<DataTemplate x:Key="DataGridTemplate">
<ListView ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding c0}" />
<DataGridTemplateColumn CellEditingTemplate="{StaticResource ResourceKey=DataGridTemplate}"
Header="c1">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding c1}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn CellEditingTemplate="{StaticResource ResourceKey=DataGridTemplate}"
Header="c2">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding c2}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn CellEditingTemplate="{StaticResource ResourceKey=DataGridTemplate}"
Header="c3">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding c3}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>