Jul 15, 2015

DataGrid with row details

A very common usage scenario when using a DataGrid control is the ability to show details about each row, typically right below the row itself. The WPF DataGrid control supports this very well, and fortunately it's also very easy to use. Let's start off with an example and then we'll discuss how it works and the options it gives you afterwards: 


<Window x:Class="WpfTutorialSamples.DataGrid_control.DataGridDetailsSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataGridDetailsSample" Height="200" Width="400">
        <Grid Margin="10">
                <DataGrid Name="dgUsers" AutoGenerateColumns="False">
                        <DataGrid.Columns>
                                <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
                                <DataGridTextColumn Header="Birthday" Binding="{Binding Birthday}" />
                        </DataGrid.Columns>
                        <DataGrid.RowDetailsTemplate>
                                <DataTemplate>
                                        <TextBlock Text="{Binding Details}" Margin="10" />
                                </DataTemplate>
                        </DataGrid.RowDetailsTemplate>
                </DataGrid>
        </Grid>
</Window>
 
 
using System;
using System.Collections.Generic;
using System.Windows;
namespace WpfTutorialSamples.DataGrid_control
{
        public partial class DataGridDetailsSample : Window
        {
                public DataGridDetailsSample()
                {
                        InitializeComponent();
                        List<User> users = new List<User>();
                        users.Add(new User() { Id = 1, Name = "John Doe", Birthday = new DateTime(1971, 7, 23) });
                        users.Add(new User() { Id = 2, Name = "Jane Doe", Birthday = new DateTime(1974, 1, 17) });
                        users.Add(new User() { Id = 3, Name = "Sammy Doe", Birthday = new DateTime(1991, 9, 2) });

                        dgUsers.ItemsSource = users;
                }
        }

        public class User
        {
                public int Id { get; set; }

                public string Name { get; set; }

                public DateTime Birthday { get; set; }

                public string Details
                {
                        get
                        {
                                return String.Format("{0} was born on {1} and this is a long description of the person.", this.Name, this.Birthday.ToLongDateString());
                        }
                }
        }
}
 
  

As you can see, I have expanded the example from previous chapters with a new property on the User class: The Description property. It simply returns a bit of information about the user in question, for our details row.
In the markup, I have defined a couple of columns and then I use the RowDetailsTemplate to specify a template for the row details. As you can see, it works much like any other WPF template, where I use a DataTemplate with one or several controls inside of it, along with a standard binding against a property on the data source, in this case the Description property.
As you can see from the resulting screenshot, or if you run the sample yourself, the details are now shown below the selected row. As soon as you select another row, the details for that row will be shown and the details for the previously selected row will be hidden.

Controlling row details visibility

Using the RowDetailsVisibilityMode property, you can change the above mentioned behavior though. It defaults toVisibleWhenSelected, where details are only visible when its parent row is selected, but you can change it to Visible or Collapsed. If you set it to Visible, all details rows will be visible all the time, like this: 


If you set it to Collapsed, all details will be invisible all the time.

More details

The first example of this article might have been a tad boring, using just a single, plain TextBlock control. Of course, with this being a DataTemplate, you can do pretty much whatever you want, so I decided to extend the example a bit, to give a better idea of the possibilities. Here's how it looks now: 

As you can see from the code listing, it's mostly about expanding the details template into using a panel, which in turn can host more panels and/or controls. Using a Grid panel, we can get the tabular look of the user data, and an Image control allows us to show a picture of the user (which you should preferably load from a locale resource and not a remote one, like I do in the example - and sorry for being too lazy to find a matching image of Jane and Sammy Doe). 

<Window x:Class="WpfTutorialSamples.DataGrid_control.DataGridDetailsSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataGridDetailsSample" Height="300" Width="300">
        <Grid Margin="10">
                <DataGrid Name="dgUsers" AutoGenerateColumns="False">
                        <DataGrid.Columns>
                                <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
                                <DataGridTextColumn Header="Birthday" Binding="{Binding Birthday}" />
                        </DataGrid.Columns>
                        <DataGrid.RowDetailsTemplate>
                                <DataTemplate>
                                        <DockPanel Background="GhostWhite">
                                                <Image DockPanel.Dock="Left" Source="{Binding ImageUrl}" Height="64" Margin="10" />
                                                <Grid Margin="0,10">
                                                        <Grid.ColumnDefinitions>
                                                                <ColumnDefinition Width="Auto" />
                                                                <ColumnDefinition Width="*" />
                                                        </Grid.ColumnDefinitions>
                                                        <Grid.RowDefinitions>
                                                                <RowDefinition Height="Auto" />
                                                                <RowDefinition Height="Auto" />
                                                                <RowDefinition Height="Auto" />
                                                        </Grid.RowDefinitions>

                                                        <TextBlock Text="ID: " FontWeight="Bold" />
                                                        <TextBlock Text="{Binding Id}" Grid.Column="1" />
                                                        <TextBlock Text="Name: " FontWeight="Bold" Grid.Row="1" />
                                                        <TextBlock Text="{Binding Name}" Grid.Column="1" Grid.Row="1" />
                                                        <TextBlock Text="Birthday: " FontWeight="Bold" Grid.Row="2" />
                                                        <TextBlock Text="{Binding Birthday, StringFormat=d}" Grid.Column="1" Grid.Row="2" />

                                                </Grid>
                                        </DockPanel>
                                </DataTemplate>
                        </DataGrid.RowDetailsTemplate>
                </DataGrid>
        </Grid>
</Window>
 
using System;
using System.Collections.Generic;
using System.Windows;
namespace WpfTutorialSamples.DataGrid_control
{
        public partial class DataGridDetailsSample : Window
        {
                public DataGridDetailsSample()
                {
                        InitializeComponent();
                        List<User> users = new List<User>();
                        users.Add(new User() { Id = 1, Name = "John Doe", Birthday = new DateTime(1971, 7, 23), ImageUrl = "http://www.wpf-tutorial.com/images/misc/john_doe.jpg" });
                        users.Add(new User() { Id = 2, Name = "Jane Doe", Birthday = new DateTime(1974, 1, 17) });
                        users.Add(new User() { Id = 3, Name = "Sammy Doe", Birthday = new DateTime(1991, 9, 2) });

                        dgUsers.ItemsSource = users;
                }
        }

        public class User
        {
                public int Id { get; set; }

                public string Name { get; set; }

                public DateTime Birthday { get; set; }

                public string ImageUrl { get; set; }
        }
}
 
 
Being able to show details for a DataGrid row is extremely useful, and 
with the WPF DataGrid it's both easy and highly customizable, as you can
 see from
    the examples provided in this tutorial.
  


No comments:

Post a Comment