2

I have a large set of data that is generated from a web service in my program. I need to display this data in a DataGrid, but the returned collections of data all have different formats (One may be 3 columns and the next 7) so I cannot create a specific object to hold this data. I am having trouble getting this information to display. Right now I am trying to use this method. I put the data into a two-dimensional list of KeyValuePairs. The Key being the Column this data would belong to, the Value being the output for that row. This is what I am trying right now.

private void SetDataValuesExecute(List<List<KeyValuePair<string,object>>> Data)
    {
        ResultsCollection = Data;
        ValuesDataGrid.Columns.Clear();
        foreach (string colName in Data[0].Select(x => x.Key).ToList())
        {
            DataGridTextColumn tempCol = new DataGridTextColumn();
            tempCol.Header = colName;
            Binding bind = new Binding();
            bind.Source = ResultsCollection.Select(x => x.FirstOrDefault(y => y.Key == colName).Value.ToString()).ToList();
            tempCol.Binding = bind;
            ValuesDataGrid.Columns.Add(tempCol);         
        }
    }

The ResultsCollection is a non-volatile variable to be used as the source of my bindings. It is a copy of all of the two-dimensional List data I need to construct the DataGrid.

This looks at the first entry an extracts the Column Header values and creates new columns based on that. The binding statement looks at each Row, grabs data for the specified Column, and tries to set that as the Column's Binding. This allows me to have both the column name and a list of all the data that goes in that column. Unfortunately binding the list of data to the column ends up not displaying any data.

So my question is: How do I need to format my data in order for the Column Binding to actually display data? Am I approaching this situation all wrong? Any help is appreciated as I am quite stumped.

Nerzugal
  • 23
  • 1
  • 3
  • If you only pass one row does it work? Pretty sure it is getting to row with less columns than the first and throwing and out of range exception. I think you are going to need to iterate thru the rows to find the max col count and then pad each row to that max count. – paparazzo Jun 14 '12 at 17:21
  • @Blam All of the Rows for each separate set of data have the exact same fields (same number of columns). I get a new set of data for the column number to change, and when that happens I am going to be clearing the DataGrid and replacing it with the new data. – Nerzugal Jun 14 '12 at 18:38

2 Answers2

3

Here's a complete working sample

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var data = new MyViewModel();

        int columnIndex = 0;

        foreach (var name in data.ColumnNames)
        {
            grid.Columns.Add(
                new DataGridTextColumn
                {
                    Header = name,
                    Binding = new Binding(
                        string.Format("Values[{0}]", columnIndex++))
                });
        }

        DataContext = data;
    }
}

public class MyViewModel
{
    public MyViewModel()
    {
        Items = new List<RowDataItem>
            {
                new RowDataItem(),
                new RowDataItem(),
                new RowDataItem(),
            };

        ColumnNames = new List<string>{ "Col 1", "Col 2", "Col 3"};
    }

    public IList<string> ColumnNames { get; private set; }

    public IList<RowDataItem> Items { get; private set; }
}

public class RowDataItem
{
    public RowDataItem()
    {
        Values = new List<string>{ "One", "Two", "Three"};    
    }

    public IList<string> Values { get; private set; }
}

The Xaml

<Grid>
    <DataGrid x:Name="grid" ItemsSource="{Binding Items}" 
              AutoGenerateColumns="False"/>
</Grid>
Phil
  • 42,255
  • 9
  • 100
  • 100
  • I tried to set it up but it still is not displaying any data. Just to clarify, I set the DataContext of my DataValuesGrid to the Items list. That should expose the Values property which I access through my binding added with `Binding = new Binding(string.Format("Values[{0}]", columnIndex++))` Each "Values" contains a List of strings representing the data for each column (column index matches item index in the row). The column headers display fine of course, but the column itself doesn't seem to be getting any data from the column. Do I need to change what I am binding on? – Nerzugal Jun 14 '12 at 18:32
  • @user1456624: Updated, hope it helps. – Phil Jun 14 '12 at 18:39
  • (Updated my UserName) Still not working even after the ItemsSource change. Structure of Items is like this => Items[index].Values[index] which contains a string representation of the value I want to output. So The index for Items takes you to each RowDataItem and the Index in Values lets you access each individual value. This is correct, right? ItemsSource = Items, DataContext is my ViewModel, Binding should be Values[0] for Column 1 and Values[1] for Columns 2 and so forth. I feel like everything is linked up correctly, but having no luck. Thanks for all the help. – Nerzugal Jun 14 '12 at 19:03
0

This is a GridView but it works. I think you need to use bind.Path but with a KVP not sure about the rest of the syntax.

WPF - Display Grid of Results With Dynamic Columns/Rows

Community
  • 1
  • 1
paparazzo
  • 44,497
  • 23
  • 105
  • 176