Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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.

like image 886
Courlu Avatar asked Apr 01 '16 15:04

Courlu


2 Answers

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.

like image 156
Rachel Avatar answered Oct 11 '22 14:10

Rachel


@courlu Everything is possible with dictionary also but most of people prefer ObservableCollection. Dictionary also inherited with IEnumerable and ICollection which tell you that dictionary also able to assign as ItemSource for wpf controls.

Genneric code of Dictionary provided by .Net : public class Dictionary : IDictionary, ICollection>, IEnumerable>, IEnumerable, IDictionary, ICollection, IReadOnlyDictionary, IReadOnlyCollection>, ISerializable, IDeserializationCallback { }

so you need to do below changes in your code

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

and if you want TwoWay mode binding then inherit dictionary class with this 2 interface INotifyCollectionChanged, INotifyPropertyChanged it will support 2 way binding also like ObservableCollection.

like image 40
Bhushan Sonawane Avatar answered Oct 11 '22 14:10

Bhushan Sonawane