WPF MVVM 将 Dictionary<String, List<String>> 绑定到数据网格

Posted

技术标签:

【中文标题】WPF MVVM 将 Dictionary<String, List<String>> 绑定到数据网格【英文标题】:WPF MVVM Bind Dictionary<String, List<String>> to datagrid 【发布时间】:2016-04-01 15:00:48 【问题描述】:

我无法以正确的布局将我的Dictionary&lt;string, List&lt;string&gt;&gt; 绑定到我的 WPF 数据网格。

这是我的数据对象:

public class Result

    public Result(string type, string name, Dictionary<string, List<string>> partners)
    
        Type = type;
        Name = name;
        Partners = partners;
    

    public string Type  get; set; 
    public string Name  get; set; 
    public Dictionary<string, List<string>> Partners  get; set; 

我填充了虚拟数据并作为我的视图模型的公共属性公开:

public class MainViewModel

    public MainViewModel()
       
        var partners = new Dictionary<string, List<string>>
        
            "Company", new List<string> "company1", "company2",
            "Operator", new List<string> "false", "true",
            "Interest", new List<string> "40%", "60%",
            "Type", new List<string> "type1", "type2"
        ;
        Asset = new Result("TestType", "TestName", partners);
    

    public Result Asset  get; set; 

我正在尝试将Partners 字典绑定到我的数据网格。每个字典条目(例如公司 / 运营商 / 兴趣 / 类型)的 Key 应该构成我的数据网格的标题,相应的值填充列。像这样:

Company | Operator | Interest | Type
company1   false       40%      type1
company2   true        60%      type2

我怎样才能做到这一点?我一直在查看this question,但数据与我想要的相反。我希望我的键作为数据网格列标题(我不介意对标题进行硬编码,因为我相信标题属性不能使用数据绑定)。到目前为止,这是我的 XAML,itemsource 已正确绑定,但我不知道如何以我需要的格式获取数据:

<DataGrid x:Name="dg" ItemsSource="Binding Asset.Partners" AutoGenerateColumns="false">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Company" Binding="Binding ?"/>
        <DataGridTextColumn Header="Operator" Binding="Binding ?"/>
        <DataGridTextColumn Header="Interest" Binding="Binding ?"/>
        <DataGridTextColumn Header="Type" Binding="Binding ?"/>
    </DataGrid.Columns>
</DataGrid>

如果我在第一列中使用Binding="Binding Value[0],那么我会在我的列中得到一个“行”值,但我希望它反过来。我也尝试过使用Binding="Binding Asset.Partners[Company]",但没有奏效。

任何帮助表示赞赏。

【问题讨论】:

不要在绑定中使用字典。出于多种不同的原因,它们很糟糕。创建一个特定的类型来保存您的键/值对并将它们放入 ObservableCollection。如果你是一个书呆子程序员,你可以创建一个 KeyedCollection 的实现,它实现了 INotifyCollectionChanged,它为你提供了字典的好处,但没有大量的麻烦。\ @Will - 在不告诉我原因的情况下告诉我他们“糟透了”并不是特别有帮助。 它们很糟糕的原因有很多,至少您遇到过其中一个。其他包括阻碍 DataTemplates 的功能、无更改通知等。正如您所了解的,它们很糟糕。坦率地说,更重要的是我对键控集合的建议。去查一下,不要在字典上浪费时间。 【参考方案1】:

我个人会创建一个对象模型来表示您的数据,并绑定到这些对象的集合。

public class MyObject

    public string Company  get; set; 
    public string Operator  get; set; 
    public string Interest  get; set; 
    public string Type  get; set; 

public MainViewModel()
   
    var partners = new ObservableCollection<MyObject>()
    
        new MyObject("company1", "false", "40%", "type1"),
        new MyObject("company2", "true", "60%", "type2")
    ;
    ...

我认为普通 DataGrid 无法满足您的要求,因为它将内容读取为“对于集合中的每一行,创建一个 DataRow 并将 DataContext 分配给该行”。在你的情况下,每一行代表整个数据网格,所以这对你不起作用。

【讨论】:

出于性能考虑,我想尝试避免为我的资产类型的属性创建额外的对象模型。我已经有了一项服务,它以字典格式返回大量数据,所以我真的希望我可以直接绑定这些数据。假设我想避免使用额外的对象模型,我最好以 DataTable 格式从服务返回数据吗?还是重组我的字典? @Courlu 一个新的对象模型应该不会影响性能并使您的代码更易于阅读,但是可以。您可以重组您的字典,以便字典中的每个项目都是每行的所有数据(new List&lt;string&gt; "company1", "false", "40%", "type1" 并与Binding Value[0] 绑定,或者使用 DataTable。就这两者而言,我更喜欢仅用于结构化数据的数据表并且不需要对 XAML 进行硬编码。 好的,非常感谢您的帮助!但是在创建大量附加对象时不会对性能产生影响吗?例如。分配内存并运行构造函数? @Courlu 不,如果将内容解析为字典或数据表实际上可能会更糟,尤其是在转换数据类型时。 @Will - Rachel 已经向我证实了这一点。你的傲慢言论没有增加任何价值。【参考方案2】:

@courlu 使用字典也可以实现一切,但大多数人更喜欢 ObservableCollection。 字典也继承了 IEnumerable 和 ICollection,它们告诉你字典也可以分配为 wpf 控件的 ItemSource。

.Net 提供的 Dictionary 通用代码: 公共类字典:IDictionary,ICollection>,IEnumerable>,IEnumerable,IDictionary,ICollection,IReadOnlyDictionary,IReadOnlyCollection>,ISerializable,IDeserializationCallback

因此您需要在代码中进行以下更改

<DataGrid x:Name="dg" ItemsSource="Binding Asset.Partners.Values" AutoGenerateColumns="false">
<DataGrid.Columns>
    <DataGridTextColumn Header="Company" Binding="Binding Company"/>
    <DataGridTextColumn Header="Operator" Binding="Binding Operator"/>
    <DataGridTextColumn Header="Interest" Binding="Binding Interest"/>
    <DataGridTextColumn Header="Type" Binding="Binding Type"/>
</DataGrid.Columns>

如果你想要 TwoWay 模式绑定然后继承字典类这个 2 接口 INotifyCollectionChanged,INotifyPropertyChanged 它将支持 2 路绑定也像 ObservableCollection。

【讨论】:

以上是关于WPF MVVM 将 Dictionary<String, List<String>> 绑定到数据网格的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Dictionary<enum, bool> 双向绑定到 WPF 中的 ListView 列?

WPF:将 ContextMenu 绑定到 MVVM 命令

无法使用 MVVM 将 WPF ChartPlotter 绑定到视图

WPF 如何将主题应用于使用 MVVM 动态创建的对象

WPF/MVVM中ObservableCollection的双向绑定和过滤

正确的 MVVM 模式 WPF 命令实现