TOC

This article is currently in the process of being translated into Polish (~14% done).

The DataGrid control:

DataGrid with row details

Bardzo często podczas używania kontrolki DataGrid, chcemy wyświetlić dodatkowe informacje o danym wierszu, zazwyczaj zaraz pod samym wierszem. W WPF kontrolka DataGrid sprawia, że jest to możliwe i zarazem łatwe. Rozpocznijmy od przykładu a następnie omówimy jego działanie, opcje i możliwości.

<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());
			}
		}
	}
}

Jak widzicie, rozszerzyłem przykład z poprzedniego rozdziału o nową właściwość w klasie "User" - właściwość "Description". Zwraca ona krótką informację na temat obiektu klasy "User" na potrzeby naszego wiersza szczegółów.

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; }
	}
}

Summary

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.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!