Welcome to MSDN Blogs Sign in | Join | Help

Dynamic creation & binding of Silverlight datagrid.

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

</SqlXml>

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>();
       while (xmlReader.MoveToNextAttribute())
       {
        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

while (xmlReader.MoveToNextAttribute()) 
{ 
         DataGridTextColumn dtextcol = new DataGridTextColumn(); 
         dtextcol.IsReadOnly = true; 
         dtextcol.Header = xmlReader.Name; 
         indexingConverter convert = new indexingConverter(); 
         Binding bind = new Binding { Converter = convert, ConverterParameter = xmlReader.Name }; 
         dtextcol.DisplayMemberBinding = bind; 
        dg.Columns.Add(dtextcol); 
} 
 
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>"; 
DataGrid dg = new DataGrid(); 
dg.AutoGenerateColumns = false; 
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 
while(xmlReader.Read()) 
{ 
if (xmlReader.HasAttributes) 
{ 
//check if the first node 
if (xmlReader.IsStartElement("SqlXml")) 
{ 
//construct the columns of the dg 
while (xmlReader.MoveToNextAttribute()) 
{ 
DataGridTextColumn dtextcol = new DataGridTextColumn(); 
dtextcol.IsReadOnly = true; 
dtextcol.Header = xmlReader.Name; 
indexingConverter convert = new indexingConverter(); 
Binding bind = new Binding { Converter = convert, ConverterParameter = xmlReader.Name ; 
dtextcol.DisplayMemberBinding = bind; 
dg.Columns.Add(dtextcol); 
} 
} 
else 
{ 
//construct the rows 
Dictionary<string, string> d = new Dictionary<string, string>(); 
while (xmlReader.MoveToNextAttribute()) 
{ 
d.Add(xmlReader.Name, xmlReader.Value); 
} 
list.Add(d); 
} 
//move the reader to elements 
xmlReader.MoveToElement(); 
} 
} 
dg.ItemsSource = list; 
LayoutRoot.Children.Add(dg); 
} 
private void Button_Click(object sender, RoutedEventArgs e) 
{ 
constructdg(); 
} 
} 
class indexingConverter : IValueConverter 
{ 
public object Convert(object value, Type targetType, object parameter, ystem.Globalization.CultureInfo culture) 
{ 
Dictionary<string, string> columnData = (Dictionary<string, string>)value; 
return columnData[parameter.ToString()]; 
} 
public object ConvertBack(object value, Type targetType, object parameter, ystem.Globalization.CultureInfo culture) 
{ 
throw new NotImplementedException(); 
} 
} 
}
Published Saturday, July 19, 2008 12:15 AM by Deepak Verma
Filed under:

Comments

# re: Dynamic creation & binding of Silverlight datagrid.

Saturday, September 13, 2008 4:43 AM by orudnev

Excellent article! It help me very much. Thank you, mr. Verma!

# SilverLight DataGrid Binding

Monday, October 06, 2008 2:44 AM by NadeemIqbal's Blog

I was working on the unbound SilverLight DataGrid and thought to write one in this regard, There are

Anonymous comments are disabled
 
Page view tracker