Note: Problem is identical to Bind Objects with generic list to wpf datagrid (unanswered) which asks for a solution involving CellTemplates and doesn't include any workarounds. I'm open to any solution, and I have a working (but non-ideal) solution.
The setup is that I have a List of Objects (Persons) that each contain a List of DataObjects.
class Person : List<DataObject>
{
public string id { get; set; }
}
class DataObject
{
public string columnName { get; set;}
public string value { get; set;}
}
The columnNames are based on User Input, but every Person has the same columnNames in their List of DataObjects (i.e. they all have a firstName column, lastName column, dateOfBirth column, all with different values).
I'd like to show these values in a DataGrid format so that the values can be edited by the user.
What I'm currently doing is using a Grid (editGrid) and adding child TextBlocks to it for each column header, and then looping through the items to add TextBoxes for each cell. This works for small numbers, but when I have 1000s of People the program lags because of the sheer number of TextBoxes and TextBlocks being created.
List<People> items;
List<string> columnHeaders;
Grid editGrid;
// Generate column headers
editGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
var columns = items.SelectMany(o => o.Select(a => a.columnName)).Distinct(StringComparer.OrdinalIgnoreCase);
foreach (string text in columns)
{
TextBlock headerText = new TextBlock();
headerText.Text = text;
Grid.SetColumn(headerText, editGrid.ColumnDefinitions.Count());
editGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
columnHeaders.Add(text);
editGrid.Children.Add(headerText);
}
// Create rows
foreach (var item in items)
{
foreach (var dataObject in item)
{
var columnNum = columnHeaders.IndexOf(dataObject.columnName);
if (columnNum != -1)
{
TextBox valueBox = new TextBox();
Binding bind = new Binding();
bind.Source = dataObject;
bind.Mode = BindingMode.TwoWay;
bind.Path = new PropertyPath("value");
BindingOperations.SetBinding(valueBox , TextBox.TextProperty, bind);
Grid.SetColumn(valueBox, columnNum);
Grid.SetRow(valueBox, editGrid.RowDefinitions.Count);
editGrid.Children.Add(valueBox);
}
}
editGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
}