Search code examples
c#wpfxamlmvvmdatagrid

WPF MVVM Bind Dictionary<String, List<String>> to datagrid


I'm having trouble binding my Dictionary<string, List<string>> to my WPF datagrid with the correct layout.

This is my data object:

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; }
}

Which I have populated with dummy data and exposed as a public property of my viewmodel:

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; }
}

I am trying to bind the Partners dictionary to my datagrid. The Key of each dictionary entry (e.g. Company / Operator / Interest / Type) should make up the headers of my datagrid, with the respective values filling the columns. Like this:

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

How can I achieve this? I've been looking at this question but the data is the other way round from how I want it. I want my keys as the datagrid column headers (I don't mind hardcoding the headers as I believe the header property can't use data binding). This is my XAML so far, itemsource is bound correctly, but I don't know how to get the data in the format I need:

<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>

If I use Binding="{Binding Value[0]} for the first column, then I get a "row" of values in my column, but I want it the other way round. I've also tried using Binding="{Binding Asset.Partners[Company]}" but that didn't work.

Any help appreciated.


Solution

  • Personally I would create an object model to represent your data, and bind to a collection of those objects.

    public class MyObject
    {
        public string Company { get; set; }
        public string Operator { get; set; }
        public string Interest { get; set; }
        public string Type { get; set; }
    }
    

    and

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

    I don't think what you're asking for is possible with a normal DataGrid because it reads things as "for each row in collection, create a DataRow and assign the DataContext to that row". In your case, each row represents the entire grid of data, so this does not work for you.