Monday, May 27, 2013

WP7 - Panorama Control Data Binding in WP7

Panorama controls are used to slide through a big content without having to completely hide the previous contents, we can consider of sliding through a horizontal page with different contents and blocks. We can use this Panorama control to show rich user interface by dividing the contents to different blocks and assigning to different items horizontally which we can slide through and access the data.

The panorama controls enables you to create the UI of an application on the horizontal canvas which can be flicked to left and right with touch.

In this article i will show you how to dynamically Bind data to Panorama Control.

Step 1
To Develop application for Windows Phone 7 devices, you need to install Windows Phone 7.1 SDK and toolkit. You can download latest SDK for Windows Phone
http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=27570

SDK 7.1.1 Update
https://dev.windowsphone.com/en-us/downloadsdk

Silverlight for Window Phone Toolkit
http://silverlight.codeplex.com/releases/view/75888

Install SDK and Toolkit on your Machine.

Step 2

Create a Window Phone Application and give the solution name as SolPanoramaControl_WP7.
To start creating a new Windows Phone application, start Microsoft Visual Studio then create a new Project and select Windows Phone Application Template,it is look like this



Click on Image for better View

Step 3
Select the Window Phone Platform,it is look like this



Click on Image for better View

Step 4
Add a Window.Phone.Controls References
To add a reference, right click the References in Solution Explorer and select Add Reference. On this dialog, Select .Net Tab,Select Microsoft.Phone.Controls,Click on Add Button,it is look like this



Click on Image for better View

Step 5
Add a System.Xml.Linq Assemble reference to the project.Right click on the project name in Solution Explorer, select Add Reference and Select System.Xml.Linq  and select OK button,it is look like this



Click on Image for better View

Step 6
Create a New Folder in the Solution and give folder name as Images and add Images in folder ,it is look like this



Click on Image for better View

Step 7
Add XML file in the solution and give the file name as ImageData.xml,it is look like this



Click on Image for better View

Step 8
The XML in the following example defines an XML document with a root node called Images. This root node contains one or more nodes called Image that include elements called ImageName and ImagePath.
<?xml version="1.0" encoding="utf-8" ?>
<Images>

  <Image>
    <ImageName>Choji Akimichi</ImageName>
    <ImagePath>../Images/Choji.png</ImagePath>
  </Image>

  <Image>
    <ImageName>Gaara</ImageName>
    <ImagePath>../Images/Gaara.jpg</ImagePath>
  </Image>

  <Image>
    <ImageName>Jiraiya</ImageName>
    <ImagePath>../Images/Jiraiya.png</ImagePath>
  </Image>

  <Image>
    <ImageName>Kakashi Hatake</ImageName>
    <ImagePath>../Images/Kakashi.jpg</ImagePath>
  </Image>

  <Image>
    <ImageName>Kiba Inuzuka</ImageName>
    <ImagePath>../Images/Kiba.png</ImagePath>
  </Image>

  <Image>
    <ImageName>Killer Bee</ImageName>
    <ImagePath>../Images/KillerBee.jpg</ImagePath>
  </Image>

  <Image>
    <ImageName>Rock Lee</ImageName>
    <ImagePath>../Images/Lee.jpg</ImagePath>
  </Image>

  <Image>
    <ImageName>Might Guy</ImageName>
    <ImagePath>../Images/Might Guy.jpg</ImagePath>
  </Image>

  <Image>
    <ImageName>Naruto Uzumaki</ImageName>
    <ImagePath>../Images/Naruto.png</ImagePath>
  </Image>

  <Image>
    <ImageName>Neji Hyuga</ImageName>
    <ImagePath>../Images/Neji.png</ImagePath>
  </Image>

  <Image>
    <ImageName>Sai</ImageName>
    <ImagePath>../Images/Sai.jpg</ImagePath>
  </Image>

  <Image>
    <ImageName>Sasuke Uchiha</ImageName>
    <ImagePath>../Images/Sasuke.jpeg</ImagePath>
  </Image>

  <Image>
    <ImageName>Shikamaru Nara</ImageName>
    <ImagePath>../Images/Shikamarunara.jpg</ImagePath>
  </Image>

  <Image>
    <ImageName>Shino Aburame</ImageName>
    <ImagePath>../Images/Shino.jpg</ImagePath>
  </Image>

  <Image>
    <ImageName>Itachi Uchiha</ImageName>
    <ImagePath>../Images/UchihaItachi.png</ImagePath>
  </Image>

  <Image>
    <ImageName>Yamato</ImageName>
    <ImagePath>../Images/Yamato.jpg</ImagePath>
  </Image>
 

</Images>

Step 9
Create an ImageEntity Class in the solution,it is look like this
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SolPanoramaControl_WP7
{
    public class ImageEntity
    {
        #region Property
        /// 
        /// Get and Set Image Name
        /// 
        public String ImageName
        {
            get;
            set;
        }

        /// 
        /// Get and Set Image Path
        /// 
        public String ImagePath
        {
            get;
            set;
        }

        #endregion
    }
}

Step 10
Create a ImageView static class in a solution for retrieving data from XML document.it is look like this
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace SolPanoramaControl_WP7
{
    public static class ImageView
    {
        #region Methods

        /// <summary>
        /// Read Data from XML File
        /// </summary>
        /// <returns>List</returns>
        public static List<ImageEntity> GetDataFromXML()
        {
            try
            {
                // Load XML Document  
                XDocument XDoc = XDocument.Load("ImageData.xml");

                // Using Linq
                //Query for retrieving all Images data from XML  
                //var Query =( from Q in XDoc.Descendants("Image")
                //            select new ImageEntity
                //            {
                //                ImageName = Q.Element("ImageName").Value,
                //                ImagePath = Q.Element("ImagePath").Value
                //            }).ToList<ImageEntity>();

               // Using Lambda Expression
                var Query = XDoc.Descendants("Image").Select(LE => new ImageEntity { ImageName = LE.Element("ImageName").Value, ImagePath = LE.Element("ImagePath").Value }).ToList<ImageEntity>();
                
                return Query;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message); 
            }
        }

        #endregion
    }
}

Step 11
Add toolkit reference in XAML,so we can Add Panorama Control in Phone Application Page,it is look like this
xmlns:PhoneControl="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"

Step 12
Now add a Panorama Control on Page,it is look like this
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <PhoneControl:Panorama x:Name="panImages" Grid.Row="0" Grid.Column="0" Title="Naruto Characters"/>
</Grid>



Finally it's look like this
<phone:PhoneApplicationPage 
    x:Class="SolPanoramaControl_WP7.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
    xmlns:PhoneControl="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
    shell:SystemTray.IsVisible="True">

Step 13
Create a HeaderTemplate for Panorama Control in phone:PhoneApplicationPage.Resources. This is where we can define header for the given panel,it is look like this
<DataTemplate x:Key="PanHeaderDataTemplate">
   <TextBlock Text="{Binding ImageName}" FontFamily="Comic Sans MS" FontSize="48" FontStyle="Italic"></TextBlock>
  </DataTemplate>

Step 14
Create a ItemTemplate for panorama Control in phone:PhoneApplicationPage.Resources. This is where we can defined content for the panel,it is look like this
<DataTemplate x:Key="PanItemDataTemplate">
   <Image Source="{Binding ImagePath}" Stretch="Uniform"/>
  </DataTemplate>


Finally HeaderTemplate and ItemTemplate look like this
<phone:PhoneApplicationPage.Resources>
  <DataTemplate x:Key="PanHeaderDataTemplate">
   <TextBlock Text="{Binding ImageName}" FontFamily="Comic Sans MS" FontSize="48" FontStyle="Italic"></TextBlock>
  </DataTemplate>
  <DataTemplate x:Key="PanItemDataTemplate">
   <Image Source="{Binding ImagePath}" Stretch="Uniform"/>
  </DataTemplate>
 </phone:PhoneApplicationPage.Resources>


Step 15
Apply HeaderTemplate  and ItemTemplate on Panorama Control,it is look like this
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <PhoneControl:Panorama x:Name="panImages" Grid.Row="0" Grid.Column="0"  Title="Naruto Characters" ItemsSource="{Binding}" HeaderTemplate="{StaticResource PanHeaderDataTemplate}" ItemTemplate="{StaticResource PanItemDataTemplate}"/>
        </Grid>

Full XAML Code
<phone:PhoneApplicationPage 
    x:Class="SolPanoramaControl_WP7.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
    xmlns:PhoneControl="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
    shell:SystemTray.IsVisible="True">
 <phone:PhoneApplicationPage.Resources>
  <DataTemplate x:Key="PanHeaderDataTemplate">
   <TextBlock Text="{Binding ImageName}" FontFamily="Comic Sans MS" FontSize="48" FontStyle="Italic"></TextBlock>
  </DataTemplate>
  <DataTemplate x:Key="PanItemDataTemplate">
   <Image Source="{Binding ImagePath}" Stretch="Uniform"/>
  </DataTemplate>
 </phone:PhoneApplicationPage.Resources>

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <!--<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>-->

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <PhoneControl:Panorama x:Name="panImages" Grid.Row="0" Grid.Column="0"  Title="Naruto Characters" ItemsSource="{Binding}" HeaderTemplate="{StaticResource PanHeaderDataTemplate}" ItemTemplate="{StaticResource PanItemDataTemplate}"/>
        </Grid>
    </Grid>
 
    <!--Sample code showing usage of ApplicationBar-->
    <!--<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>-->

</phone:PhoneApplicationPage>

Step 16
Now Bind the data in Panorama Control in Code Behind,it is look like this
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;
using Microsoft.Phone.Controls;

namespace SolPanoramaControl_WP7
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            // Call Bind Images Function on Phone Application Loaded Event
            // this is Lambda Expression Event handler
            this.Loaded += (s, e) =>
            {
                try
                {
                    // Call Bind Image Function
                    BindImages();

                    // Set Default Panoram Item.
                    panImages.DefaultItem = panImages.Items[3];
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message); 
                }
            };

            
        }

        #region Methods

        /// <summary>
        /// Bind Image to Panaroma Control
        /// </summary>
        private void BindImages()
        {
            try
            {
                // Store Data in List Object
                List<ImageEntity> ListImageEntityObj = ImageView.GetDataFromXML();

                // Check List Object is Null or Not
                if (ListImageEntityObj != null)
                {
                    // Check List Object Count  
                    if (ListImageEntityObj.Count > 0)
                    {
                        // Bind Data in Panorama Control. 
                        panImages.DataContext = ListImageEntityObj;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message); 
            }
        }

        #endregion
    }
}

Run the Project.

Output





Flick Images to Left and Right.

Download
Download Source Code

Monday, May 20, 2013

WPF -DataGrid RowDetailsTemplate in WPF

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
Create a WPF Application and give solution name as SolDataGridRowDetailTemplate_ExpandCollapse_WPF.


Step 4
Create a New Folder in Solution and give the Folder Name as ORD,it is look like this



Click on Image for Better View

Step 5
Add a Linq to Sql class,Select the ORD folder,right click on Add new Item,select LINQ to SQL classes from installed Visual Studio templates and name it NorthwindDC and click on add button,it is look like this



Click on Image for Better View

Step 6

Open a O/R Designer by double click on NorthwindDC.dbml,it is look like this


Click on Image for Better View


Click on Image for Better View

Visual studio provides an object-relational mapping designer,called the O/R Designer which allows you to visually design the object to database mapping.

Step 7
Create a Employee object that will use LINQ to SQL to map to this table.go to the Server Explorer,select Northwind database,go to the Tables and select Employees table,it is look like this


Click on Image for Better View

Drag and drop Employees table from Server explorer onto the design surface of the O/R Designer,it is look like this


Click on Image for Better View

Step 8
Create a Employee Static Class for retrieving data from Employee Table using Linq or Lambda Expression,it is look like this
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SolDataGridRowDetailTemplate_ExpandCollapse_WPF
{
    public static class Employee
    {
        #region Methods
        /// <summary>
        /// Get Emplyee Data From Table
        /// </summary>
        /// <returns>List</returns>
        public static List<ORD.Employee> GetEmployeeData()
        {
            try
            {
                ORD.NorthwindDCDataContext DC = new ORD.NorthwindDCDataContext();

                // Using Linq 

                //var Query =( from Q in DC.Employees
                //            select new ORD.Employee
                //            {
                //                FirstName = Q.FirstName,
                //                LastName = Q.LastName,
                //                City = Q.City,
                //                Notes = Q.Notes
                //            }).ToList<ORD.Employee>();

                // Using Lambda Expression

                var Query = DC.Employees.Select(LE => new ORD.Employee() { FirstName=LE.FirstName,LastName=LE.LastName,City=LE.City,Notes=LE.Notes }).ToList<ORD.Employee>();

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

        #endregion
    }
}

Step 9
Now add DataGrid Control on window,it is look like this
<Grid>
        <DataGrid x:Name="dgEmployee" Grid.Row="0" Grid.Column="0" AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="False" ItemsSource="{Binding}" RowDetailsVisibilityMode="Collapsed" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
           

        </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 10
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>
        <DataGrid x:Name="dgEmployee" Grid.Row="0" Grid.Column="0" AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="False" ItemsSource="{Binding}" RowDetailsVisibilityMode="Collapsed" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button x:Name="btnExpandCollapse" Content="+" Click="btnExpandCollapse_Click_1"></Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>


Click on Image for Better View

Step 11
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>
        <DataGrid x:Name="dgEmployee" Grid.Row="0" Grid.Column="0" AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="False" ItemsSource="{Binding}" RowDetailsVisibilityMode="Collapsed" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button x:Name="btnExpandCollapse" Content="+" Click="btnExpandCollapse_Click_1"></Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="FirstName" Binding="{Binding FirstName}"></DataGridTextColumn>
                <DataGridTextColumn Header="LastName" Binding="{Binding LastName}"></DataGridTextColumn>
                <DataGridTextColumn Header="City" Binding="{Binding City}"></DataGridTextColumn>
            </DataGrid.Columns>
            
        </DataGrid>
  </Grid>



Click on Image for Better View

Step 12
Now finally add RowDetailsTemplate in DataGrid to display addition data in place, associated with a bound row.it is look like this
<Grid>
        <DataGrid x:Name="dgEmployee" Grid.Row="0" Grid.Column="0" AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="False" ItemsSource="{Binding}" RowDetailsVisibilityMode="Collapsed" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button x:Name="btnExpandCollapse" Content="+" Click="btnExpandCollapse_Click_1"></Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="FirstName" Binding="{Binding FirstName}"></DataGridTextColumn>
                <DataGridTextColumn Header="LastName" Binding="{Binding LastName}"></DataGridTextColumn>
                <DataGridTextColumn Header="City" Binding="{Binding City}"></DataGridTextColumn>
            </DataGrid.Columns>
            <DataGrid.RowDetailsTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Notes}" Width="400" HorizontalAlignment="Left" TextWrapping="Wrap"></TextBlock>
                </DataTemplate>
            </DataGrid.RowDetailsTemplate>
        </DataGrid>
    </Grid>


Click on Image for Better View

Full Code of XAML
<Window x:Class="SolDataGridRowDetailTemplate_ExpandCollapse_WPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataGrid RowDetailsTemplate" Height="350" Width="525" Loaded="Window_Loaded_1">
    <Grid>
        <DataGrid x:Name="dgEmployee" Grid.Row="0" Grid.Column="0" AutoGenerateColumns="False" IsReadOnly="True" CanUserAddRows="False" ItemsSource="{Binding}" RowDetailsVisibilityMode="Collapsed" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button x:Name="btnExpandCollapse" Content="+" Click="btnExpandCollapse_Click_1"></Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="FirstName" Binding="{Binding FirstName}"></DataGridTextColumn>
                <DataGridTextColumn Header="LastName" Binding="{Binding LastName}"></DataGridTextColumn>
                <DataGridTextColumn Header="City" Binding="{Binding City}"></DataGridTextColumn>
            </DataGrid.Columns>
            <DataGrid.RowDetailsTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Notes}" Width="400" HorizontalAlignment="Left" TextWrapping="Wrap"></TextBlock>
                </DataTemplate>
            </DataGrid.RowDetailsTemplate>
        </DataGrid>
    </Grid>
</Window>

Step 13
Now Bind the data in DataGrid Control in Code Behind on Window Load Event,it is look like this
#region Methods

        /// <summary>
        /// Bind Employee Data to DataGrid
        /// </summary>
        private void BindEmployeeData()
        {
            try
            {
                //Get Employee List
                List<ORD.Employee> ListEmployeeobj = Employee.GetEmployeeData();

                // Check the List is Null or Not
                if (ListEmployeeobj != null)
                {
                    // Check the List Count is grether than 0
                    if (ListEmployeeobj.Count >0)
                    {
                        // Bind List to DataGrid
                        dgEmployee.DataContext = ListEmployeeobj;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message); 
            }
        }

        #endregion

        private void Window_Loaded_1(object sender, RoutedEventArgs e)
        {
            try
            {
                // Call bind Employee Data Function
                BindEmployeeData();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        }

Step 14
On Button ExapndCollapse Click event,add the following code,it is look like this 
private void btnExpandCollapse_Click_1(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);

                    // Check the DataGridRow Object is Null or Not
                    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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SolDataGridRowDetailTemplate_ExpandCollapse_WPF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }


        #region Methods

        /// <summary>
        /// Bind Employee Data to DataGrid
        /// </summary>
        private void BindEmployeeData()
        {
            try
            {
                //Get Employee List
                List<ORD.Employee> ListEmployeeobj = Employee.GetEmployeeData();

                // Check the List is Null or Not
                if (ListEmployeeobj != null)
                {
                    // Check the List Count is grether than 0
                    if (ListEmployeeobj.Count >0)
                    {
                        // Bind List to DataGrid
                        dgEmployee.DataContext = ListEmployeeobj;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message); 
            }
        }

        #endregion

        private void Window_Loaded_1(object sender, RoutedEventArgs e)
        {
            try
            {
                // Call bind Employee Data Function
                BindEmployeeData();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message); 
            }
        }

        private void btnExpandCollapse_Click_1(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);

                    // Check the DataGridRow Object is Null or Not
                    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



Click on Image for Better View

Download
Download Source Code