Sunday, July 7, 2013

Silverlight - DataGrid RowDetailsTemplate in Silverlight 5

RowDetailsTemplate is a great feature that to view details information about a bound row in a DataGrid on demand so that the details portion is displayed in place within the DataGrid.

The DataGrid.RowDetailsTemplate property accepts a data template  that can be used to display additional data in place, associated with a bound row. This feature comes handy in many scenarios—to provide master-detail data where multiple detail records need to be displayed for a top-level row or where additional information, not otherwise bound to top-level columns, needs to be displayed adjacent to a row.

The DataGrid.RowDetailsVisibilityMode property controls the visibility of the row details information at DataGrid scope. That is, setting it to Visible keeps it always visible for every bound row, whereas setting it to Visible When Selected makes the details portion of a row visible when the row is selected and collapsed back when selection moves off to another row. To control row details visibility in code, set this property to Collapsed, which hides row details for every row, and instead use the DataGridRow.DetailsVisibility property on the individual row.

Let See how to use RowDetailsTemplate in DataGrid.

Step 1
Download Northwind database from the following link.
http://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46a0-8da2-eebc53a68034&displaylang=en

Step 2
Attach a Northwind database into MS-SQL server.

Step 3
Download Silverlight 5 Tools for Visual Studio 2010 *
http://www.microsoft.com/en-us/download/details.aspx?id=28358

No need to Install Silverlight 5 tools in Visual Studio 2012

Step 4
Create a Silverlight Application and give the solution name as SolDataGridRowDetailTemplate_ExpandCollapse_SL.



Click on image for better view

Note: Select Web Project Type as ASP.NET Web site.

Step 5
 Install Entity Framework 5 from Nuget Package Source.it is look like this




Step 6
Select ASP.net Web project(SolDataGridRowDetailTemplate_ExpandCollapse_SL.Web) and right click on web project,select Add ASP.Net Folder and add App_Code folder in Solution.

In App_Code folder Create a another folder Name EF.



Click on image for better view

Step 7
Select EF folder and Right click on EF folder,Select Add New Item from Context menu,select ADO.NET Entity Data Model from Templates and rename the file as NorthwindModel.edmx, Click on Add button.it's look like this.



Click on image for better view

Generate Model from Database,it is look like this



Click on image for better view

Connect Database to the Application,it is look like this.



Click on image for better view

Select Northwind Database and Save Entity Connection String in Web.Config File.

Select Database Objects.it is look like this



Click on image for better view

Select Employee table and click on Finish button.

Now Entities Created based on table,it is look like this



Click on image for better view

Step 8
Select a ASP.net Web application(SolDataGridRowDetailTemplate_ExpandCollapse_SL.Web) and Add a WCF Service,right click on solution,select Add New Item,select WCF Service from installed Visual Studio templates and name it NorthwindService.svc and click on add button.


it will add two CS file in App_Code Folder I.E.(INorthwindService.cs,NorthwindService.cs)



Click on image for better view

Step 9
Now we will make some modification to the OperationContract. Remove default DoWork method from the INorthwindService interface.Add a new Method named as GetEmployeeData which return List<EF.Employee>,it is look like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "INorthwindService" in both code and config file together.
[ServiceContract]
public interface INorthwindService
{
    [OperationContract]
    List<EF.Employee> GetEmployeeData();

}


Step 10
Implement INorthwindService interface in NorthwindService class and get Employee data from databse,it is look like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "NorthwindService" in code, svc and config file together.
public class NorthwindService : INorthwindService
{
    public List<EF.Employee> GetEmployeeData()
    {
        try
        {
            EF.NorthwindEntities NEObj = new EF.NorthwindEntities();

            // Using Linq Query
            //var Query = (from Q in NEObj.Employees
            //             select new
            //             {
            //                 FirstName = Q.FirstName,
            //                 LastName = Q.LastName,
            //                 City = Q.City,
            //                 Notes = Q.Notes
            //             }).ToList().Select(E => new EF.Employee() 
            //             { FirstName = E.FirstName, LastName = E.LastName, City = E.City, Notes = E.Notes });


            // Using Lambda Expression
            var Query = NEObj.Employees
            .Select(LE => new { FirstName = LE.FirstName, LastName = LE.LastName, City = LE.City, Notes = LE.Notes }).ToList()
            .Select(E => new EF.Employee() { FirstName = E.FirstName, LastName = E.LastName, City = E.City, Notes = E.Notes });

            return Query.ToList();
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message); 
        }
    }
}

Step 11
Add a reference of  WCF Service in silverlight application(SolDataGridRowDetailTemplate_ExpandCollapse_SL).Right click the Silverlight project and add a Service reference,it is look like this



Click on image for better view

Step 12

Add a WCF service in the silverlight application.Add Service Reference dialog box will open and click on Discover button and give the namesapace name as NorthwindServiceReference,it's look like this




Click on image for better view

Step 13
Now Add DataGrid Control from ToolBox in Page,it is look like this
<Grid x:Name="LayoutRoot" Background="White">

        <sdk:DataGrid x:Name="dgEmployee" Grid.Row="0" Grid.Column="0" GridLinesVisibility="All" AutoGenerateColumns="False" IsReadOnly="True"  ItemsSource="{Binding}" RowDetailsVisibilityMode="Collapsed" RowBackground="#AA0481FD" AlternatingRowBackground="#FF4B707E">
            
        </sdk:DataGrid>
       
    </Grid>

Note: In the DataGrid set the RowDetailsVisibilityMode to collapse. This will ensure that row is not expanded when user clicks on the row.

Step 14
Select DataGrid and Add DataGridTemplateColumn in DataGrid where we add Button control in Column to expand or collapse the DetaileRow.,it is look like this
<Grid x:Name="LayoutRoot" Background="White">

        <sdk:DataGrid x:Name="dgEmployee" Grid.Row="0" Grid.Column="0" GridLinesVisibility="All" AutoGenerateColumns="False" IsReadOnly="True"  ItemsSource="{Binding}" RowDetailsVisibilityMode="Collapsed" RowBackground="#AA0481FD" AlternatingRowBackground="#FF4B707E">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTemplateColumn>
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button x:Name="btnExpandCollapse" Content="+" Click="btnExpandCollapse_Click"></Button>
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
       
    </Grid>


Click on image for better view

Step 15
Select DataGrid Control and Add three DataGridTextColumn in DataGrid where we bind Employee details such as FirstName,LastName and City,it is look like this
<Grid x:Name="LayoutRoot" Background="White">

        <sdk:DataGrid x:Name="dgEmployee" Grid.Row="0" Grid.Column="0" GridLinesVisibility="All" AutoGenerateColumns="False" IsReadOnly="True"  ItemsSource="{Binding}" RowDetailsVisibilityMode="Collapsed" RowBackground="#AA0481FD" AlternatingRowBackground="#FF4B707E">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTemplateColumn>
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button x:Name="btnExpandCollapse" Content="+" Click="btnExpandCollapse_Click"></Button>
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
               
                <sdk:DataGridTextColumn Header="FirstName" Binding="{Binding FirstName}"/>
                <sdk:DataGridTextColumn Header="LastName" Binding="{Binding LastName}"/>
                <sdk:DataGridTextColumn Header="City" Binding="{Binding City}"/>
            </sdk:DataGrid.Columns>
           
        </sdk:DataGrid>
       
    </Grid>


Click on image for better view

Step 16
Now finally add RowDetailsTemplate in DataGrid to display addition data in place, associated with a bound row.it is look like this
<Grid x:Name="LayoutRoot" Background="White">

        <sdk:DataGrid x:Name="dgEmployee" Grid.Row="0" Grid.Column="0" GridLinesVisibility="All" AutoGenerateColumns="False" IsReadOnly="True"  ItemsSource="{Binding}" RowDetailsVisibilityMode="Collapsed" RowBackground="#AA0481FD" AlternatingRowBackground="#FF4B707E">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTemplateColumn>
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button x:Name="btnExpandCollapse" Content="+" Click="btnExpandCollapse_Click"></Button>
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
               
                <sdk:DataGridTextColumn Header="FirstName" Binding="{Binding FirstName}"/>
                <sdk:DataGridTextColumn Header="LastName" Binding="{Binding LastName}"/>
                <sdk:DataGridTextColumn Header="City" Binding="{Binding City}"/>
            </sdk:DataGrid.Columns>
            
            <sdk:DataGrid.RowDetailsTemplate>
                <DataTemplate>
                    <Border BorderThickness="2" CornerRadius="5" Background="LightBlue"  HorizontalAlignment="Stretch">
                        <TextBlock Text="{Binding Notes}" Width="400" HorizontalAlignment="Left" TextWrapping="Wrap" Margin="20,0,0,0"></TextBlock>
                    </Border>
                </DataTemplate>
            </sdk:DataGrid.RowDetailsTemplate>

        </sdk:DataGrid>
       
    </Grid>


Click on image for better view

Full XAML Code
<UserControl
    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"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
    x:Class="SolDataGridRowDetailTemplate_ExpandCollapse_SL.MainPage"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">

        <sdk:DataGrid x:Name="dgEmployee" Grid.Row="0" Grid.Column="0" GridLinesVisibility="All" AutoGenerateColumns="False" IsReadOnly="True"  ItemsSource="{Binding}" RowDetailsVisibilityMode="Collapsed" RowBackground="#AA0481FD" AlternatingRowBackground="#FF4B707E">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTemplateColumn>
                    <sdk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button x:Name="btnExpandCollapse" Content="+" Click="btnExpandCollapse_Click"></Button>
                        </DataTemplate>
                    </sdk:DataGridTemplateColumn.CellTemplate>
                </sdk:DataGridTemplateColumn>
               
                <sdk:DataGridTextColumn Header="FirstName" Binding="{Binding FirstName}"/>
                <sdk:DataGridTextColumn Header="LastName" Binding="{Binding LastName}"/>
                <sdk:DataGridTextColumn Header="City" Binding="{Binding City}"/>
             
            </sdk:DataGrid.Columns>
            
            <sdk:DataGrid.RowDetailsTemplate>
                <DataTemplate>
                    <Border BorderThickness="2" CornerRadius="5" Background="LightBlue"  HorizontalAlignment="Stretch">
                        <TextBlock Text="{Binding Notes}" Width="400" HorizontalAlignment="Left" TextWrapping="Wrap" Margin="20,0,0,0"></TextBlock>
                    </Border>
                </DataTemplate>
            </sdk:DataGrid.RowDetailsTemplate>

        </sdk:DataGrid>
       
    </Grid>
</UserControl>

Step 17
Bind the data to DataGrid Control in Code Behind on UserControl Load Event using Lambda Expression,it is look like this
public MainPage()
        {
            InitializeComponent();

            /// Initialize Load Event using Lambda Expression
            this.Loaded += (s, o) => 
            {
                try
                {
                    // Call WCF Service
                    NorthwindServiceReference.NorthwindServiceClient NCRobj = new NorthwindServiceReference.NorthwindServiceClient();

                    // Wire up the Async Completed  handler Using Lambda Expression
                    NCRobj.GetEmployeeDataCompleted += (sender, e) =>
                    {
                        // Bind Employee Data to DataGrid Control
                        dgEmployee.DataContext = e.Result;
                    };

                    // Call WCF Method
                    NCRobj.GetEmployeeDataAsync();

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message); 
                }
            };
        }

Step 18
On Button ExapndCollapse Click event,add the following code,it is look like this 
private void btnExpandCollapse_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Get the Selected Row Button Object  
                Button ExpandCollapseObj = (Button)sender; 

                // Check the Button Object is null or Not  
                if (ExpandCollapseObj != null)
                {
                    // Return the Contains which specified element  
                    DataGridRow DgrSelectedRowObj = DataGridRow.GetRowContainingElement(ExpandCollapseObj);

                    if (DgrSelectedRowObj != null)
                    {
                        // if Button Content is "+" then Visible Row Details   
                        if (ExpandCollapseObj != null && ExpandCollapseObj.Content.ToString() == "+")
                        {
                            DgrSelectedRowObj.DetailsVisibility = System.Windows.Visibility.Visible;
                            ExpandCollapseObj.Content = "-";
                        }
                        // else Collapsed row Details  
                        else
                        {
                            DgrSelectedRowObj.DetailsVisibility = System.Windows.Visibility.Collapsed;
                            ExpandCollapseObj.Content = "+";
                        }  
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        }

Full Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SolDataGridRowDetailTemplate_ExpandCollapse_SL
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();

            /// Initialize Load Event using Lambda Expression
            this.Loaded += (s, o) => 
            {
                try
                {
                    // Call WCF Service
                    NorthwindServiceReference.NorthwindServiceClient NCRobj = new NorthwindServiceReference.NorthwindServiceClient();

                    // Wire up the Async Completed  handler Using Lambda Expression
                    NCRobj.GetEmployeeDataCompleted += (sender, e) =>
                    {
                        // Bind Employee Data to DataGrid Control
                        dgEmployee.DataContext = e.Result;
                    };

                    // Call WCF Method
                    NCRobj.GetEmployeeDataAsync();

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message); 
                }
            };
        }

        private void btnExpandCollapse_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Get the Selected Row Button Object  
                Button ExpandCollapseObj = (Button)sender; 

                // Check the Button Object is null or Not  
                if (ExpandCollapseObj != null)
                {
                    // Return the Contains which specified element  
                    DataGridRow DgrSelectedRowObj = DataGridRow.GetRowContainingElement(ExpandCollapseObj);

                    if (DgrSelectedRowObj != null)
                    {
                        // if Button Content is "+" then Visible Row Details   
                        if (ExpandCollapseObj != null && ExpandCollapseObj.Content.ToString() == "+")
                        {
                            DgrSelectedRowObj.DetailsVisibility = System.Windows.Visibility.Visible;
                            ExpandCollapseObj.Content = "-";
                        }
                        // else Collapsed row Details  
                        else
                        {
                            DgrSelectedRowObj.DetailsVisibility = System.Windows.Visibility.Collapsed;
                            ExpandCollapseObj.Content = "+";
                        }  
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        }
    }
}

Output

Download
Download Source Code

2 comments: