The main goal of the Row Details feature is to let you present additional information about a row. This makes row details the perfect candidate for presenting hierarchical data.

My sample uses two kinds of business objects – a football club and its players. As you might expect each club has some players. The master grid will show our clubs and when the user wants to see some additional information about a club he will be presented with the row details. Our first goal is to define what will these details look like. We would like to see some general information about the club and its current squad (or part of it for the sake of the example).

To do that we will create a UserControl containing an Image and another RadGridView. As you might have guessed, this last grid will be showing the club’s squad. The Image will show the logo of the club. Here is what the control looks like:

   1: <UserControl x:Class="ToggleRowDetails.ClubDetailsControl"
   2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   4: xmlns:controls="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls"
   5: xmlns:telerik="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.GridView">
   6: <Grid x:Name="LayoutRoot">
   7: <Grid.RowDefinitions>
   8: <RowDefinition Height="Auto"/>
   9: <RowDefinition Height="Auto"/>
  10: </Grid.RowDefinitions>
  11: <StackPanel HorizontalAlignment="Left">
  12: <Image Name="logoImage" Source="{Binding LogoPath}" Stretch="None" Margin="8"/>
  13: <TextBlock Text="Players" FontSize="14" FontWeight="Light" Margin="8,0" />
  14: </StackPanel>
  15: <telerik:RadGridView Name="playersGrid" Grid.Row="1" Margin="8,2,8,8" Width="652" controls:StyleManager.Theme="Office_Blue"
  16: HorizontalAlignment="Left"
  17: ColumnsWidthMode="Fill"
  18: ItemsSource="{Binding Players}"
  19: AutoGenerateColumns="False"
  20: ShowGroupPanel="False"
  21: IsReadOnly="True"
  22: Background="White">
  23: <telerik:RadGridView.Columns>
  24: <telerik:GridViewDataColumn Header="Name" DataMemberBinding="{Binding Name}"/>
  25: <telerik:GridViewDataColumn Header="Number" DataMemberBinding="{Binding Number}"/>
  26: <telerik:GridViewDataColumn Header="Position" DataMemberBinding="{Binding Position}"/>
  27: <telerik:GridViewDataColumn Header="Country" DataMemberBinding="{Binding Country}"/>
  28: </telerik:RadGridView.Columns>
  29: </telerik:RadGridView>
  30: </Grid>
  31: </UserControl>

Next we need to tell the grid to use this control to display its row details. Simply set its RowDetailsTemplate like this:

   1: ...
   2: <Grid.Resources>
   3: <DataTemplate x:Key="ClubDetailsTemplate">
   4: <local:ClubDetailsControl/>
   5: </DataTemplate>
   6: </Grid.Resources>
   7: <telerik:RadGridView RowDetailsTemplate="{StaticResource ClubDetailsTemplate}"
   8:                      ...
   9: />
  10: ...
  11:  

Now we are almost ready. Typically, you would want the row details to show up when a user selects a row. This is exactly what the RowDetailsVisibilityMode property of the grid takes care of. The GridViewRowDetailsVisibilityMode enumeration has three values – Collapsed, Visible and VisibleWhenSelected which do exactly what their names suggest.

We, however, would like to go a step further. If you are not content with the grid governing the row details behavior of all rows you can redefine this for each and every row. Each GridViewRow has a property called DetailsVisibility which overrides the behavior imposed by the grid. The mechanism is simple – if this property is null then the row obeys its parent grid about showing and hiding row details. Otherwise it is what it is. We will use this to create a custom column with a toggle button that will show / hide the row details.

To do that we will inherit from GridViewColumn and override the CreateCellElement method. There we will return our “special” toggle button that knows about its parent GridViewRow and controls the DetailsVisibility:

   1: public class DetailsToggleColumn : GridViewColumn
   2: {
   3: public override FrameworkElement CreateCellElement(GridViewCell cell, object dataItem)
   4:     {
   5:         var parentRow = cell.ParentRow as GridViewRow;
   6: if (parentRow != null)
   7:         {
   8: return new DetailsToggleButton(parentRow);
   9:         }
  10:  
  11: return null;
  12:     }
  13:  
  14:     ...
  15: }

The button is very simple as well. It has its IsChecked property bound to the DetailsVisibility property of its parent row with the help of the almighty BooleanToVisibilityConverter:

   1: public partial class DetailsToggleButton : UserControl
   2: {
   3: private readonly GridViewRow parentRow;
   4: 
   5: public DetailsToggleButton(GridViewRow parentRow)
   6:     {
   7: this.InitializeComponent();
   8: 
   9: this.parentRow = parentRow;
  10: 
  11: this.Init();
  12:     }
  13:  
  14: private void Init()
  15:     {
  16:         var b1 = new Binding("IsChecked")
  17:         {
  18:             Source = this.toggleButton,
  19:             Mode = BindingMode.TwoWay,
  20:             Converter = new BooleanToVisibilityConverter()
  21:         };
  22:  
  23: this.parentRow.SetBinding(GridViewRow.DetailsVisibilityProperty, b1);
  24:     }
  25: }

Well, I lied. The designer mate sitting next to me saw the toggle button and styled it in Blend to give it this finished look, but you can examine this in the source code bundle.

And that’s all about it. Here is our grid with a “toggle hierarchy row details”:

ToggleHierarchyRowDetails

Here is the Source Code

Enjoy!


Related Posts

Comments