How to: Display and Configure Row Details in the DataGrid Control
Microsoft Silverlight will reach end of support after October 2021. Learn more.
Each row in the Silverlight DataGrid can be expanded to display a row details section. The row details section is defined by a DataTemplate that specifies the appearance of the section and the data to be displayed.
The row details section can be displayed for selected rows, displayed for all rows, or it can be collapsed. The row details section can also be frozen so that it does not scroll horizontally when the DataGrid is scrolled.
To display a row details section using inline XAML
Create a DataTemplate that defines the appearance of the row details section.
For more information, see How to: Customize Data Display with Data Templates.
Place the DataTemplate inside the <DataGrid.RowDetailsTemplate> tags.
<sdk:DataGrid x:Name="dataGrid1" Height="400" IsReadOnly="True" > <sdk:DataGrid.RowDetailsTemplate> <!-- Begin row details section. --> <DataTemplate> <Border BorderBrush="Black" BorderThickness="1" Background="Tan"> <StackPanel Orientation="Horizontal"> <StackPanel> <StackPanel Orientation="Horizontal"> <!-- Controls are bound to Task properties. --> <TextBlock FontSize="16" Foreground="MidnightBlue" Text="{Binding Name}" Margin="0,0,10,0" VerticalAlignment="Bottom" /> <TextBlock FontSize="12" Text="Due Date: " VerticalAlignment="Bottom"/> <sdk:DatePicker SelectedDate="{Binding DueDate, Mode=TwoWay}" VerticalAlignment="Bottom" /> <TextBlock FontSize="12" Text=" Complete:" VerticalAlignment="Bottom" /> <CheckBox IsChecked="{Binding Complete, Mode=TwoWay}" VerticalAlignment="Center" /> </StackPanel> <TextBlock FontSize="12" Text="Notes: " /> <TextBox FontSize="12" Text="{Binding Notes, Mode=TwoWay}" Width="420" TextWrapping="Wrap"/> </StackPanel> </StackPanel> </Border> </DataTemplate> <!-- End row details section. --> </sdk:DataGrid.RowDetailsTemplate> </sdk:DataGrid>
To display a row details section using a DataTemplate resource
Create a DataTemplate that defines the appearance of the row details section.
For more information, see How to: Customize Data Display with Data Templates.
Identify the DataTemplate by assigning a value to the x:Key Attribute.
Bind the DataTemplate to the DataGrid's RowDetailsTemplate property.
<data:DataGrid RowDetailsTemplate="{StaticResource templateReference}"/>
To change the visibility of a row details section
Set the RowDetailsVisibilityMode property to a value of the DataGridRowDetailsVisibilityMode enumeration.
The following code example handles the SelectionChanged event of a ComboBox, and sets the RowDetailsVisibilityMode to the option selected in the ComboBox.
' Set the row details visibility to the option selected in the combo box. Private Sub cbRowDetailsVis_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Dim cb As ComboBox = sender Dim cbi As ComboBoxItem = cb.SelectedItem If Me.dataGrid1 IsNot Nothing Then If cbi.Content.ToString() = "Selected Row (Default)" Then Me.dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected ElseIf cbi.Content.ToString() = "None" Then Me.dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Collapsed ElseIf cbi.Content.ToString() = "All" Then Me.dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Visible End If End If End Sub
// Set the row details visibility to the option selected in the combo box. private void cbRowDetailsVis_SelectionChanged(object sender, RoutedEventArgs e) { ComboBox cb = sender as ComboBox; ComboBoxItem cbi = cb.SelectedItem as ComboBoxItem; if (this.dataGrid1 != null) { if (cbi.Content.ToString() == "Selected Row (Default)") dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected; else if (cbi.Content.ToString() == "None") dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Collapsed; else if (cbi.Content.ToString() == "All") dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Visible; } }
To prevent a row details section from scrolling horizontally
Set the AreRowDetailsFrozen property to true.
The following code example sets the AreRowDetailsFrozen property to the IsChecked value of a CheckBox named cb.
Me.dataGrid1.AreRowDetailsFrozen = cb.IsChecked
this.dataGrid1.AreRowDetailsFrozen = (bool)cb.IsChecked;
Example
The following code example creates a List<T> of Task objects, and displays the task list in a DataGrid named dataGrid1. The DataGrid is read-only, but displays a row details section that allows editing. The row details section is bound to the same DataContext as the DataGridRow. In order for changes to the source data made in the row details section to be displayed in the DataGridRow, the Task class implements the INotifyPropertyChanged interface. A user interface is also provided for setting row details options.
<!-- NOTE:
By convention, the sdk prefix indicates a URI-based XAML namespace declaration
for Silverlight SDK client libraries. This namespace declaration is valid for
Silverlight 4 only. In Silverlight 3, you must use individual XAML namespace
declarations for each CLR assembly and namespace combination outside the scope
of the default Silverlight XAML namespace. For more information, see the help
topic "Prefixes and Mappings for Silverlight Libraries".
-->
<UserControl x:Class="DGRowDetails.Page"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="https://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<ScrollViewer VerticalScrollBarVisibility="Auto" BorderThickness="0" Padding="0">
<StackPanel x:Name="LayoutRoot" Background="White" Margin="5">
<StackPanel Margin="0,0,0,5">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Black" BorderThickness="1" Padding="3" Width="180">
<StackPanel>
<TextBlock Text="Row Details Visibility" FontSize="12"/>
<ComboBox SelectionChanged="cbRowDetailsVis_SelectionChanged">
<ComboBoxItem Content="Selected Row (Default)" IsSelected="True" />
<ComboBoxItem Content="All"/>
<ComboBoxItem Content="None"/>
</ComboBox>
<CheckBox Content="Freeze Row Details" Margin="0,3,0,0"
Checked="cbFreezeRowDetails_Changed"
Unchecked="cbFreezeRowDetails_Changed" />
</StackPanel>
</Border>
</StackPanel>
</StackPanel>
<sdk:DataGrid x:Name="dataGrid1" Height="400" IsReadOnly="True" >
<sdk:DataGrid.RowDetailsTemplate>
<!-- Begin row details section. -->
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="1" Background="Tan">
<StackPanel Orientation="Horizontal">
<StackPanel>
<StackPanel Orientation="Horizontal">
<!-- Controls are bound to Task properties. -->
<TextBlock FontSize="16" Foreground="MidnightBlue" Text="{Binding Name}"
Margin="0,0,10,0" VerticalAlignment="Bottom" />
<TextBlock FontSize="12" Text="Due Date: " VerticalAlignment="Bottom"/>
<sdk:DatePicker SelectedDate="{Binding DueDate, Mode=TwoWay}" VerticalAlignment="Bottom" />
<TextBlock FontSize="12" Text=" Complete:" VerticalAlignment="Bottom" />
<CheckBox IsChecked="{Binding Complete, Mode=TwoWay}"
VerticalAlignment="Center" />
</StackPanel>
<TextBlock FontSize="12" Text="Notes: " />
<TextBox FontSize="12" Text="{Binding Notes, Mode=TwoWay}"
Width="420" TextWrapping="Wrap"/>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
<!-- End row details section. -->
</sdk:DataGrid.RowDetailsTemplate>
</sdk:DataGrid>
</StackPanel>
</ScrollViewer>
</UserControl>
Partial Public Class Page
Inherits UserControl
Public Sub New()
InitializeComponent()
' Create a list to store task data.
Dim taskList As List(Of Task) = New List(Of Task)
Dim itemsCount As Integer = 15
' Generate some task data and add it to the task list.
For index = 1 To itemsCount
taskList.Add(New Task() With _
{.Name = "Task " & index.ToString(), _
.DueDate = Date.Now.AddDays(index), _
.Complete = (index Mod 3 = 0), _
.Notes = "Task " & index.ToString() & " is due on " & Date.Now.AddDays(index) & ". Lorum ipsum..." _
})
Next
Me.dataGrid1.ItemsSource = taskList
End Sub
' Set the row details visibility to the option selected in the combo box.
Private Sub cbRowDetailsVis_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs)
Dim cb As ComboBox = sender
Dim cbi As ComboBoxItem = cb.SelectedItem
If Me.dataGrid1 IsNot Nothing Then
If cbi.Content.ToString() = "Selected Row (Default)" Then
Me.dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected
ElseIf cbi.Content.ToString() = "None" Then
Me.dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Collapsed
ElseIf cbi.Content.ToString() = "All" Then
Me.dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Visible
End If
End If
End Sub
' Freeze the row details if the check box is checked.
Private Sub cbFreezeRowDetails_Changed(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim cb As CheckBox = sender
If Me.dataGrid1 IsNot Nothing Then
Me.dataGrid1.AreRowDetailsFrozen = cb.IsChecked
End If
End Sub
End Class
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace DGRowDetails
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
// Create a list to store task data.
List<Task> taskList = new List<Task>();
int itemsCount = 15;
// Generate some task data and add it to the task list.
for (int i = 1; i <= itemsCount; i++)
{
taskList.Add(new Task()
{
Name = "Task " + i.ToString(),
DueDate = DateTime.Now.AddDays(i),
Complete = (i % 3 == 0),
Notes = "Task " + i.ToString() + " is due on "
+ DateTime.Now.AddDays(i) + ". Lorum ipsum..."
});
}
this.dataGrid1.ItemsSource = taskList;
}
// Set the row details visibility to the option selected in the combo box.
private void cbRowDetailsVis_SelectionChanged(object sender, RoutedEventArgs e)
{
ComboBox cb = sender as ComboBox;
ComboBoxItem cbi = cb.SelectedItem as ComboBoxItem;
if (this.dataGrid1 != null)
{
if (cbi.Content.ToString() == "Selected Row (Default)")
dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
else if (cbi.Content.ToString() == "None")
dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Collapsed;
else if (cbi.Content.ToString() == "All")
dataGrid1.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Visible;
}
}
// Freeze the row details if the check box is checked.
private void cbFreezeRowDetails_Changed(object sender, RoutedEventArgs e)
{
CheckBox cb = sender as CheckBox;
if (this.dataGrid1 != null)
this.dataGrid1.AreRowDetailsFrozen = (bool)cb.IsChecked;
}
}
}
Imports System.ComponentModel
Public Class Task
Implements System.ComponentModel.INotifyPropertyChanged
' The Task class implements INotifyPropertyChanged so that
' the datagrid row will be notified of changes to the data
' that are made in the row details section.
' Private task data.
Private m_Name As String
Private m_DueDate As Date
Private m_Complete As Boolean
Private m_Notes As String
' Define the public properties.
Property Name() As String
Get
Return Me.m_Name
End Get
Set(ByVal value As String)
If Not (value = Me.m_Name) Then
Me.m_Name = value
NotifyPropertyChanged("Name")
End If
End Set
End Property
Property DueDate() As Date
Get
Return Me.m_DueDate
End Get
Set(ByVal value As Date)
If Not (value = Me.m_DueDate) Then
Me.m_DueDate = value
NotifyPropertyChanged("DueDate")
End If
End Set
End Property
Property Complete() As Boolean
Get
Return Me.m_Complete
End Get
Set(ByVal value As Boolean)
If Not (value = Me.m_Complete) Then
Me.m_Complete = value
NotifyPropertyChanged("Complete")
End If
End Set
End Property
Property Notes() As String
Get
Return Me.m_Notes
End Get
Set(ByVal value As String)
If Not (value = Me.m_Notes) Then
Me.m_Notes = value
NotifyPropertyChanged("Notes")
End If
End Set
End Property
' Implement INotifyPropertyChanged interface.
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(ByVal propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
using System;
using System.ComponentModel;
namespace DGRowDetails
{
public class Task : System.ComponentModel.INotifyPropertyChanged
{
// The Task class implements INotifyPropertyChanged so that
// the datagrid row will be notified of changes to the data
// that are made in the row details section.
// Private task data.
private string m_Name;
private DateTime m_DueDate;
private bool m_Complete;
private string m_Notes;
// Define the public properties.
public string Name
{
get { return this.m_Name; }
set
{
if (value != this.m_Name)
{
this.m_Name = value;
NotifyPropertyChanged("Name");
}
}
}
public DateTime DueDate
{
get { return this.m_DueDate; }
set
{
if (value != this.m_DueDate)
{
this.m_DueDate = value;
NotifyPropertyChanged("DueDate");
}
}
}
public bool Complete
{
get { return this.m_Complete; }
set
{
if (value != this.m_Complete)
{
this.m_Complete = value;
NotifyPropertyChanged("Complete");
}
}
}
public string Notes
{
get { return this.m_Notes; }
set
{
if (value != this.m_Notes)
{
this.m_Notes = value;
NotifyPropertyChanged("Notes");
}
}
}
// Implement INotifyPropertyChanged interface.
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
See Also