In the previous article I described the basics of Data Binding in Silverlight. In this article I will demonstrate How to Bind Data grid with different data sources like:
- Binding with Static Collection/List
- Binding with XML
- Binding with Database via WCF Services
- Binding with Database via WCF RIA Services
To setup an example let’s create a new Silverlight project is VS 2010 called “DataBinding”. See “How to create Silverlight application in VS 2010” for more information. Let’s create add a new Class file called “Item.cs” with Item Class as following:
namespace DataBinding
{
public class Item
{
public string ItemNumber { get; set;}
public string ItemDescription { get; set; }
public int Quantity { get; set; }
public Item()
{
}
public Item(string ItemNumber, string ItemDescription, int Quantity)
{
this.ItemNumber= ItemNumber;
this.ItemDescription = ItemDescription;
this.Quantity = Quantity;
}
}
}
We will refer the above class to bind the data gird. Let’s add a DataGrid on the MainPage.xaml page by drag & drop the data grid control from the toolbox. You will see the below in MainPate.xaml page..
<UserControl x:Class="DataBinding.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="513" d:DesignWidth="662"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
>
<Grid x:Name="LayoutRoot" Background="White" Height="540" Width="664">
<sdk:DataGrid AutoGenerateColumns="False"
Height="100" HorizontalAlignment="Left"
Margin="12,21,0,0" Name="dataGrid1"
VerticalAlignment="Top" Width="311" />
</Grid>
</UserControl>
Let’s change the property AutoGenerateColumns to True and create a Collection of Item class in Item.cs class file as following:
public class ItemsCollection : Collection-
{
public ItemsCollection()
{
Add(new Item("1", "Item Name1", 1));
Add(new Item("2", "Item Name2", 2));
Add(new Item("3", "Item Name3", 3));
}
}
On the MainPage’s constructor write following to bind the data grid with collection object
dataGrid1.ItemsSource = new ItemsCollection();
Same thing you can also do by setting the ItemSource property in XAML and then assign DataContext of datagrid as following:
ItemsSource="{Binding}"
dataGrid1.DataContext = new ItemsCollection();
Now the run the project you will the data grid have three column and three rows of items we added in the collection.
Binding with XML
In Silverlight, you cannot bind Data Grid directly to XML data. A possible workaround for this is to convert the XML to CLR objects, and then bind to the CLR object.
Let say we have following XML file called “ItemList.xml” for the list of items…
<?xml version="1.0" encoding="utf-8" ?>
<ItemList>
<Item ItemNumber="1" ItemDescription="Item Name1" Quantity="1" />
<Item ItemNumber="2" ItemDescription="Item Name2" Quantity="2" />
<Item ItemNumber="3" ItemDescription="Item Name3" Quantity="3" />
</ItemList>
Let’s first create a function which returns the Item object by passing the XML Element
private Item GetItem(XElement el)
{
Item s = new Item();
s.ItemDescription = el.Attribute("ItemDescription").Value;
s.ItemNumber = el.Attribute("ItemNumber").Value;
s.Quantity = Convert.ToInt32(el.Attribute("Quantity").Value.ToString());
return s;
}
We can have two cases.
- XML is in Silverlight project
- XML is on Sever Side(we have URL or xml file is in the Client Bin Folder)
When XML is in Silverlight project
Let’s a create function which return the list of items
public List<Item> GetItemList()
{
List<Item> itemList = new List<Item>();
XElement doc = XElement.Load(@"Data/ItemList.xml");
itemList = (from el in doc.Elements()
select GetItem(el)).ToList();
return itemList;
}
We can assign the Itemsource of data grid as following :
dataGrid1.ItemsSource = GetItemList();
When XML is on Sever Side
We need to create a asynchronous method to get the content of XML file from the server and then create the List of items from the xml. See the code below
private void ReadDataFromXML()
{
Uri url = new Uri("ItemList.xml", UriKind.Relative);
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(url);
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
dataGrid1.ItemsSource = GetItemList(e.Result);
}
public List<Item> GetItemList(string xmlcontent)
{
List<Item> itemList = new List<Item>();
XElement doc = XElement.Parse(xmlcontent);
itemList = (from el in doc.Elements()
select GetItem(el)).ToList();
return itemList;
}
You will need to add reference of System.Xml.Linq.
Binding with Database
Silverlight project doesn't support normal ADO.NET objects like DataTable, DataSet, DataColumn, Database connection providers like SqlConnection, OledbConnection objects. You can use System.Data namespace but that contains Services related stuffs not ADO.NET stuffs. To get the data from the database we need to create WCF Data Services or WCF RIA Services… Read “Introduction to WCF Services” to get more details.
Create Database
Let’s fist create a database and a table called tblItem as following:
CREATE TABLE [dbo].[tblItem](
[ItemNumber] [varchar](50) NULL,
[ItemDescription] [varchar](50) NULL,
[Quantity] [int] NULL
)
Let’s insert few records in the table…
INSERT INTO [tblItem]
([ItemNumber]
,[ItemDescription]
,[Quantity])
VALUES ('1','Item Name1',1),
('2','Item Name3',2),
('3','Item Name3',3)
Creating WCF Service
Now create “CItem” class in web project for Item as following...
using System.Runtime.Serialization;
namespace DataBinding.Web
{
[DataContract]
public class CItem
{
[DataMember]
public string ItemNumber { get; set;}
[DataMember]
public string ItemDescription { get; set; }
[DataMember]
public int Quantity { get; set; }
}
}
Let’s add Silverlight-enabled WCF Service in the Web project called “DataService.svc”
Let’s create a function in the wcf service so that it return the list of items as following:
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Data;
using System.Data.SqlClient;
namespace DataBinding.Web
{
[ServiceContract(Namespace = "")]
public class DataService
{
static string connectionString = "Data Source=.\\sql2008;Initial Catalog=DataBinding;Integrated Security=True;";
[OperationContract]
public List<CItem> GetItems()
{
SqlConnection sqlConnection = new SqlConnection(connectionString);
DataSet objSet = new DataSet();
SqlCommand sqlCommand = new SqlCommand();
sqlCommand.Connection = sqlConnection;
sqlCommand.CommandText = "Select * FROM tblItem";
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
sqlDataAdapter.SelectCommand = sqlCommand;
sqlDataAdapter.Fill(objSet);
List<CItem> lstResult = new List<CItem>();
CItem objEmployee;
if (objSet.Tables.Count > 0)
{
foreach (DataRow dr in objSet.Tables[0].Rows)
{
objEmployee = new CItem();
objEmployee.Quantity = Convert.ToInt32(dr["Quantity"]);
objEmployee.ItemDescription = dr["ItemDescription"].ToString();
objEmployee.ItemNumber = dr["ItemNumber"].ToString();
lstResult.Add(objEmployee);
}
}
return lstResult;
}
}
}
Consuming WCF Service in Silverlight project
To consume the WCF service we just created we need to add Service Reference of that WCF service in the Silverlight project.
Now we need to create object of the WCF service client and event handler which will get the results sent by the WCF service as following:
private void ReadDataFromDatabase()
{
DaService.DataServiceClient t = new DaService.DataServiceClient();
t.GetItemsCompleted += new EventHandler<DaService.GetItemsCompletedEventArgs>(GetItemCompleted);
t.GetItemsAsync();
}
void GetItemCompleted(object sender, DaService.GetItemsCompletedEventArgs e)
{
dataGrid7.ItemsSource = e.Result;
}
You are done… Run the project you will see the grid is show data from the database with three rows and column we inserted.
So far we set the AutoGenerateColumns property of data grid to True. So those columns are generated automatically for all the properties of Item Class.Let’s define the column and set the binding property in XAML:
<sdk:DataGrid AutoGenerateColumns="False"
Height="100" HorizontalAlignment="Left"
Margin="341,21,0,0" Name="dataGrid2"
VerticalAlignment="Top" Width="311" >
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn CanUserReorder="True" CanUserResize="True"
CanUserSort="True" Width="Auto"
Binding="{Binding ItemNumber}"
Header="ItemNumber"/>
<sdk:DataGridTextColumn CanUserReorder="True" CanUserResize="True"
CanUserSort="True" Width="Auto"
Binding="{Binding ItemDescription}"
Header="ItemDescription"/>
<sdk:DataGridTextColumn CanUserReorder="True" CanUserResize="True"
CanUserSort="True" Width="Auto"
Binding="{Binding Quantity}"
Header="Quantity"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
In the next article we will see “How to Bind Data Grid with Database via WCT RIA Services” and what are different column types in Datagrid…
You may find below little bit interesting…
What is difference between ItemSource and DataContext
- DataContext expects an object type where ItemsSource expects IEnumerable type objects.
- DataContext is a dependency property is exposed by FrameworkElement base class,where as ItemsSource is defined by the ItemsControl class. All the descendants of FrameworkElement can utilize the DataContext property and set an object to its value. But we can only set a type of IEnumerable (or instance of class that derives from).
- DataContext does not generate template, it only used to hold common data for other controls to bind. In terms of ItemsSource property, it is mainly used to generate template regardless of you set it in XAML or in the code behind.
- DataContext is mainly used to hold common data that other child want to share. Thus it can be inherited by other child elements without problem. But for ItemsSource, it not used to share data in the visual tree. It is only valid for the element that defined. There is still one thing to be noted is that the child element can override the DataContext of the perent DataContext no mater directly or indirectly.