将datagrid列绑定到viewmodel

问题描述 投票:0回答:2

我有一个完美的视图模型,它基本上具有以下属性:

    -ItemCollection
       - Name
       - Type
       - DayCollection
           - DateOfDay
           - Value

我现在正试图让视图工作以呈现如下数据:

Name | Type  | DateOfDay1 | DateOfDay2 | DateOfDay3 ...
Dave | Actual| 1.2        | 1.8        | 5.4
Mary | Actual| 3.4        | 2.3        | 6.4
...

问题是,当我将ItemCollection绑定到视图中的Datagrid时,视图显示:

Name | Type  | DayCollection
Dave | Actual| (Collection)
Mary | Actual| (Collection)

至关重要 - 与下面的一些示例不同,我的用例更简单 - ItemCollection中的所有项目在DayCollection中总是具有完全相同的天数 - 即我的表格的所有行都将具有相同的列数。虽然请注意不同的ItemCollections可能有不同的天数(但在ItemCollection中所有Items将具有相同的天数) - 所以我不能简单地展开上面的视图模型并具有ItemCollection,例如:

-ItemCollection
    - Name
    - Type
    - Day1
    - Day2
    - Day3

因为一个ItemCollection(表)可能有5天另外30天。

我发现以下文章谈论动态添加列 - 我不需要在编辑期间添加或删除列 - 列数已修复:

https://www.codeproject.com/Articles/899637/Dynamic-Columns-in-a-WPF-DataGrid-Control-Part

http://www.unixresources.net/faq/320089.shtml

https://www.codeproject.com/Tips/676530/How-to-Add-Columns-to-a-DataGri

我发现上面的样本过于复杂,我认为这是一个非常简单的用例 - 可变数量的项目(行),但每行中固定(预定)的列数[上面的最后一篇文章是非常的写得很好]。我希望我可以使用重复的xaml来简单地定义列:

<DataGrid ...>
    <DataGrid.Columns>
         <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
         <DataGridTextColumn Header="Type" Binding="{Binding Type}" />    
         <Repeater ItemsSource="{Binding DayCollection}">
             <DataGridTextColumn Header="{Binding DateOfDay}" Binding="{Binding Value}" />
         </Repeater>
    </DataGrid.Columns>
</DataGrid>

像上面这样的东西将是一个简单的用例的简单解决方案,但显然不支持

我确信这个简单的问题有一个简单的解决方案,但我找不到任何方法来实现上述目标 - 上面引用的文章似乎过多,并且设计用于更复杂的用例(可变数量的列和列可以动态添加和删除) - 我不需要这种灵活性,我不想实现它只是为了固定数量的列。

我唯一的另一个想法就是在我的视图模型中有一个像ToDataTable()这样的属性,它会从我的viewmodel输出一个包含完整行和列的数据表,我可以将数据网格绑定到,但这似乎是一个浪费 - 然后更难以检查更新并将这些更新引导到上面工作视图模型中已存在的业务逻辑。

是否有一个简单的解决方案,或者我是否为一个简单的用例提交了很多代码?

c# wpf mvvm datagrid
2个回答
3
投票

视图模型的重点是以视图可以轻松使用的格式准备数据。如果您的视图模型没有这样做,那么它就不是“完美地工作”,事实上它甚至没有完成它本应该做的一项工作!你需要做的是创建一个中间结构,你的数据以正确的格式解压缩,然后use data-binding to create your columns dynamically

正如您已经发现的那样,使用诸如行为等之类的东西确实存在这个问题的通用解决方案。行为通常比代码隐藏更干净和通用,但它们仍然是视图层的一部分,所以这些解决方案实际上只是乐队-aids试图将坏视角模型数据放入视图中。您应该做的是解决更基本的潜在问题并解决视图模型层中的问题。

有很多不同的方法可以做到这一点,但一个简单的解决方案是将所有数据打包到DataTable中,然后将DataGrid绑定到DataTable。这段代码应该给出一个非常粗略的想法:

<DataGrid ItemsSource="{Binding MyTable}" />

...

public class MainViewModel : ViewModelBase
{
    public DataTable MyTable { get; } = new DataTable();
    private int NumColumns = 3;

    public MainViewModel()
    {
        this.MyTable = new DataTable();
        this.MyTable.Columns.Add("Name");
        this.MyTable.Columns.Add("Type");
        for (int i = 1; i <= NumColumns; i++)
            this.MyTable.Columns.Add($"Day {i}");

        var row = this.MyTable.NewRow();
        row.ItemArray = new object[] { "Tom", "Type A", "1.2", "2.3", "3.4" };
        this.MyTable.Rows.Add(row);

        row = this.MyTable.NewRow();
        row.ItemArray = new object[] { "Dick", "Type B", "2.3", "3.4", "4.5" };
        this.MyTable.Rows.Add(row);

        row = this.MyTable.NewRow();
        row.ItemArray = new object[] { "Harry", "Type C", "3.4", "4.5", "5.6" };
        this.MyTable.Rows.Add(row);
    }
}

enter image description here


0
投票

经过几天寻找更好的解决方案后,我终于选择了上面的第三个链接。我仍然认为这是一个非常复杂的解决方案,应该非常简单,但它可以工作并且非常可重用。

https://www.codeproject.com/Tips/676530/How-to-Add-Columns-to-a-DataGri

© www.soinside.com 2019 - 2024. All rights reserved.