For a Silverlight application, I have a requirement to dynamically create datagrid from xml data.
Following two samples show the format of xml returned from a webservice.
1. <SqlXml empid=”varchar” deptid=”varchar” empname=”varchar”>
<row empid="1001 " deptid="1 " empname="Sam" />
<row empid="1002 " deptid="3 " empname="Bill" />
</SqlXml>
2. <SqlXml empid=”varchar” deptid=”varchar” empname=”varchar”>
<row deptid="1" deptname="Fin" />
<row deptid="3 " deptname="Sales" />
Now, I want to write a Silverlight application that can parse the above xml format and create the datagrid columns dynamically.
Following is the solution I used to create my application.
Step 1: Create the datagrid
The important part for creating datagrid columns dynamically is to set AutogenerateColumns property to false otherwise it may throw an exception
DataGrid dg = new DataGrid();
dg.AutoGenerateColumns = false;
Step 2: Read the xml and add columns to the datagrid
while (xmlReader.MoveToNextAttribute())
{
DataGridTextColumn dtextcol = new DataGridTextColumn();
dtextcol.IsReadOnly = true;
dtextcol.Header = xmlReader.Name;
dg.Columns.Add(dtextcol);
}
Step 3: Parse the xml to a list of dictionary strings and assign it to Itemsource property
while(xmlReader.Read())
if (xmlReader.HasAttributes)
Dictionary<string, string> d = new Dictionary<string, string>();
d.Add(xmlReader.Name, xmlReader.Value);
list.Add(d);
//move the reader to elements
xmlReader.MoveToElement();
Step 4: Assign the list to datagrid’s itemsource property
dg.ItemsSource = list;
Step 5: Now, how can I bind the dictionary object to the datagridcolumn I thought of implementing it as
dtextcol.DisplayMemberBinding = d[xmlReader.Name];
I guess indexers aren't supported as of Silverlight Beta 2. The workaround is to use converter and a converter param. so the above code will change to
indexingConverter convert = new indexingConverter();
Binding bind = new Binding { Converter = convert, ConverterParameter = xmlReader.Name };
dtextcol.DisplayMemberBinding = bind;
class indexingConverter : IValueConverter
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
Dictionary<string, string> columnData = (Dictionary<string, string>)value;
return columnData[parameter.ToString()];
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
throw new NotImplementedException();
Wherein the first parameter passed to Convert function is the dictionary object and the third parameter is the attribute name.
Following is the full code
namespace datagrid
public partial class Page : UserControl
public Page()
InitializeComponent();
private void constructdg()
//generic xml returned from a service
String xml = "<SqlXml empid=\"varchar\" deptid=\"varchar\" empname=\"varchar\"><row empid=\"1001\" deptid=\"1\" empname=\"Sam\" /><row empid=\"1002\" deptid=\"3\" empname=\"Bill\" /></SqlXml>";
XmlReader xmlReader = XmlReader.Create(new StringReader(xml));
//list containing the row elements
List<Dictionary<string, string>> list = new List<Dictionary<string, string>>();
//create the columns of the datagrid from the first node
//check if the first node
if (xmlReader.IsStartElement("SqlXml"))
//construct the columns of the dg
Binding bind = new Binding { Converter = convert, ConverterParameter = xmlReader.Name ;
else
//construct the rows
LayoutRoot.Children.Add(dg);
private void Button_Click(object sender, RoutedEventArgs e)
constructdg();
public object Convert(object value, Type targetType, object parameter, ystem.Globalization.CultureInfo culture)
public object ConvertBack(object value, Type targetType, object parameter, ystem.Globalization.CultureInfo culture)