Tuesday, 10 July 2012

DynamicBind datagrid columns in Silverlight DataGrid

This article explains how to create dynamic columns and rows for a Silverlight DataGrid control. It helps create a new DataGrid from scratch in code-behind, populated with values from a System.Collections.Generic.Dictionary.

Binding dynamic content to DataGrid

The following function binds a StringTable object to a Silverlight DataGrid control. The StringTable object is a simple Dictionary explained below.

private void BindStringTableToDataGrid(StringTable table, DataGrid dataGrid)
    dataGrid.ItemsSource = table.Values;
    dataGrid.AutoGenerateColumns = false;
    foreach (string columnName in table.ColumnNames)
        DataGridTextColumn textColumn = new DataGridTextColumn();
        textColumn.Header = columnName;
        textColumn.Binding = new Binding();
        textColumn.Binding.Converter = new ColumnValueSelector();
        textColumn.Binding.ConverterParameter = columnName;

Note that AutoGenerateColumns property of DataGrid is set to "false". This is to prevent DataGrid from creating columns for other properties of StringRow like Count, Keys, etc.
About StringTable

The StringTable is a simple Dictionary class with row-indices as Keys and StringRow as Values.
public class StringTable : Dictionary<int, StringRow>
    public List<string> ColumnNames { get; set; }
    public StringTable()
        ColumnNames = new List<string>();

where StringRow is an alias of the following declaration. Key is the column-name and Value is the column-value of the corresponding row.
 1public class StringRow : Dictionary<string, string>

For more sophisticated table data-structure with advanced helper and utility methods, .

The ColumnValueSelector

The ColumnValueSelector is a converter class extended from IValueConverter. This converter is used to get the column value of the current row.
01public class ColumnValueSelector : IValueConverter
03    object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
04    {
05        StringRow row = (StringRow)value;
06        string columnName = (string)parameter;
07        return (row[columnName]);
08    }
10    object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
11    {
12        throw new NotImplementedException();
13    }

How this works?

Since ItemsSource property of DataGrid expects a collection object, we assign it the Values property of the StringTable object. In StringTable, the column-values of each row is represented by a StringRow i.e. Dictionary<string, string>. That is, each StringRow is created as one row in the DataGrid, and each entry in the StringRow is created as one column in that row. The ColumnValueSelector is used to get the column value of the corresponding row. The column-name is passed to the converter through ConverterParameter property of the datagrid column's Binding property.

No comments :