Silverlight2.0 Nested DataGrid using Silverlight-enabled WCF Services and LINQ to SQL
May 13, 2009 at 7:39 pm 2 comments
Create new project.
- Create a new Silverlight project in Visual Studio 2008 or Visual Web Developer 2008 and select a new Web Site to host the Silverlight application. Name it “Silverlight_MasterDetailsGrid”
- When the IDE opens, we have 2 projects listed. Silverlight_MasterDetailsGrid and Silverlight_MasterDetailsGrid.Web. The Web application has a Silverlight_MasterDetailsGrid.TestPage.aspx which hosts the .zap file created by Silverlight_MasterDetailsGrid.
Add Linq to SQL Classes
- Select Silverlight_MasterDetailsGrid.Web project in Solution Explorer and right click to add new item.
- Select “LINQ to SQL Classes”.
- Name the File to “Nwind.dbml” and click OK
- Drag and Drop the Orders and Order_Details table from Server Explorer.
- Right click on any blank space in Nwind.dbml file and select “Properties”.
- Set SerializationMode to “Unidirectional”. [Currently, WCF does not support Cyclic Reference Serialization (like in dbml file the Order Table contains a Order_Detail filed and Order_Detail Table contains the Order field. Setting the SerializationMode to Unidirectional will serialize only tables excluding the referential table/fields)
- Click Save. [The Nwind.Designer.VB file will have all the classes with the DataContract attribute applied to Order and Order_Detail tables and DataMember attribute to the properties of these tables. This will make these classes serializable thus ready to be used in WCF Services]
Add WCF Service.
- Select Silverlight_MasterDetailsGrid.Web project in Solution Explorer and right click to add new item.
- Select “Silverlight-enabled WCF Service”
- Name the file “WCFService.svc” and click “OK”
- The Visual Studio will open the WCFService.svc.vb file with a class with dummy Service Contract and Operation Contract.
- Click “Project” menu and select “Add New Item”.
- Select Interface and Name it “IWCFService.vb”. Click “OK”
- Imports two Interfaces, System.ServiceModel and System.ServiceModel.Activation
- Add ServiceContract attribute to IWCFService Interface and define two OperationContracts GetOrders and GetAllOrderDetails. Thus the IWCFService.vb should look like:
| Imports System.ServiceModelImports System.ServiceModel.Activation<ServiceContract()> _
Public Interface IWCFService <OperationContract()> _ Function GetOrders() As IEnumerable(Of Order) <OperationContract()> _ Function GetAllOrderDetails() As IEnumerable(Of Order_Detail) End Interface |
9. Open WCFService.svc.vb and delete all content of the Class and its ServiceContract attribute.
10. Implement IWCFService Interface in the WCFService Class. This class will have only one attribute [AspNetCompatibilityRequirements].
11. Implement the GetOrders and GetAllOrderDetails functions
12. The WCFService.svc.vb should now look like:
| Imports System.ServiceModelImports System.ServiceModel.Activation<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> _
Public Class WCFService Implements IWCFService Public Function GetOrders() As IEnumerable(Of Order) Implements IWCFService.GetOrders Dim DC As New NwindDataContext() Return DC.Orders.AsEnumerable() End Function Public Function GetAllOrderDetails() As IEnumerable(Of Order_Detail) Implements IWCFService.GetAllOrderDetails Dim DC As New NwindDataContext() Return DC.Order_Details.AsEnumerable End Function End Class |
13. Open Web.Config file and change the Contract in Endpoint section from Silverlight_MasterDetailsGrid.Web.WCFService to Silverlight_MasterDetailsGrid.Web.IWCFService
This finalizes our WCF service and makes it ready to be hosted.
Defining the Service Reference in client to consume the above created WCFService
- In the Solution Explorer, expand the “Silverlight_MasterDetailsGrid” project. Right click on it and click “Add Service Reference”.
- Click “Discover” to locate the WCFService automatically.
- Name the Service “NwindWcfReference”
Adding DataGrid to Silverlight application
- Open Page.xaml and drag and drop the DataGrid from ToolBox to the Code window, under LayoutRoot grid.
- Name the DataGrid by adding x:Name attribute to “GrdOrders”.
- Set AutoGenerateColumns to True.
- Set ItemsSource to “{Binding}”. This will bind the DataGrid to its DataContext.
Thus, the DataGrid definition should look like:
<data:DataGrid x:Name=”GrdOrders” AutoGenerateColumns=”True” ItemsSource=”{Binding}”/>
Binding GrdOrders DataGrid to Orders
- Open Page.xaml.vb.
- Imports Silverlight_MasterDetailsGrid.NwindWcfReference
- Imports System.Collections.ObjectModel
- Add a class level variable Orders of type ObservableCollection(Of Order)
- Add another class level variable wcfClient of type WCFServiceClient
- In the constructor initialize the Orders and wcfClient variables after InitializeComponent()
- In the Page_Loaded event add the event handler to the wcfClient, using AddHandler WcfClient.GetOrdersCompleted, AddressOf GetOrdersCompleted
- Call the WcfClient.GetOrdersAsync() method
- Define the GetOrdersCompleted method Public Sub GetOrdersCompleted(ByVal sender As Object, ByVal e As GetOrdersCompletedEventArgs)
- Set Orders = e.Result
- Set GrdOrders.DataContext = Orders
Run the application and see the all records with all the columns of Orders table are displayed in the DataGrid.
Defining RowDetailsTemplate to create nested DataGrid
- Open the Page.xaml and add the RowDetailsTemplate to GrdOrders.
- Define the DataTemplate.
- Add DataGrid to DataTemplate and name it GrdDetails.
- Set it’s AutoGenerateColumn property to “True”
Thus the resulting XAML of Complete DataGrid should look like:
|
<data:DataGrid x:Name=”GrdOrders” AutoGenerateColumns=”True” ItemsSource=”{Binding}”> <data:DataGrid.RowDetailsTemplate> <DataTemplate> <data:DataGrid x:Name=”GrdDetails” AutoGenerateColumns=”True” ItemsSource=”{Binding Order_Details}”></data:DataGrid> </DataTemplate> </data:DataGrid.RowDetailsTemplate> </data:DataGrid> |
Calling the GetAllOrderDetailsAsync and binding the inner DataGrid to Order_Detail
- Add another class level variable allOrder_Detais of type ObservableCollection(Of Order_Detail)
- In the Page_Loaded event, add the WcfClient.GetAllOrderDetailsCompleted handler.
- In the GetOrdersCompleted event, make a call to WcfClient.GetAllOrderDetailsAsync()
- Define the GetAllOrderDetailsCompleted and add following code that
- Fetches all the rows and columns of the Order_Details table and store it in allOrder_Detais variable.
- Loop through all the Order in Orders and using LINQ query find all the OrderDetails from allOrder_Detais whose OrderId is equal to Order.OrderID
- Create a temporary ObservalbleCollection(of Order_Detail) and insert items of Order_Detail fetched in steps b.
- Assign the temporary collection created in steps c to Order.Order_Details
- Set the GrdOrders.DataContext to Orders
The resulting GetAllOrderDetailsCompleted function should be:
Public Sub GetAllOrderDetailsCompleted(ByVal sender As Object, ByVal e As GetAllOrderDetailsCompletedEventArgs)
allOrder_Detais = e.Result
For Each o As Order In Orders
Dim tempOrder_Details = From allDetails In allOrder_Detais Where allDetails.OrderID = o.OrderID Select allDetails
Dim tempDetails As New ObservableCollection(Of Order_Detail)
For Each item In tempOrder_Details
tempDetails.Add(item)
Next
o.Order_Details = tempDetails
Next
GrdOrders.DataContext = Orders
End Sub
OUTPUT: Click any row of Master DataGrid to display the related OrderDetails in nested DataGrid.

Entry filed under: Silverlight. Tags: Silverlight DataBinding, Silverlight DataGrid, Silverlight LINQ to SQL, Silverlight Nested DataGrid, Silverlight Nested DataGrid LINQ to SQL, Silverlight-enabled WCF Services, Silverlight2.0.
1.
Sunil | October 27, 2009 at 5:30 pm
Hi,
Thanks for such a very nice article, if possible can you plz mail an example program of Nested Datagrid . It will be of great help if you can send me an example of it.
Thanks in advance
2.
Lakshmi | June 11, 2010 at 1:12 pm
hi..
Article is good.
Can you please povide the solution?
or atleast a sample solution which directly binds some static data, instead of using WCF and linq?