WPF Datagrid RowDetailsTemplate visibility bound to a property

27,799

Solution 1

Looking at the WPF toolkit source code each DataGridRow has a DetailsVisibility property.

I put a button (just for testing) in the first column.

<toolkit:DataGridTemplateColumn>
    <toolkit:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Button x:Name="buttonDetails" Content="Hello" ButtonBase.Click="Details_Click" />
        </DataTemplate>
    </toolkit:DataGridTemplateColumn.CellTemplate>
</toolkit:DataGridTemplateColumn>

When the button is clicked, find the clicked row and toggle the property.

   private void Details_Click(object sender, RoutedEventArgs e)
    {
      try
      {
        // the original source is what was clicked.  For example 
        // a button.
        DependencyObject dep = (DependencyObject)e.OriginalSource;

        // iteratively traverse the visual tree upwards looking for
        // the clicked row.
        while ((dep != null) && !(dep is DataGridRow))
        {
          dep = VisualTreeHelper.GetParent(dep);
        }

        // if we found the clicked row
        if (dep != null && dep is DataGridRow)
        {
          // get the row
          DataGridRow row = (DataGridRow)dep;

          // change the details visibility
          if (row.DetailsVisibility == Visibility.Collapsed)
          {
            row.DetailsVisibility = Visibility.Visible;
          }
          else
          {
            row.DetailsVisibility = Visibility.Collapsed;
          }
        }
      }
      catch (System.Exception)
      {
      }
    }

I have not explored doing this via databinding.

Solution 2

Using pure XAML (+ a converter):

XAML:

<DataGrid.RowHeaderTemplate>
    <DataTemplate>
        <ToggleButton
            IsChecked="{Binding Path=DetailsVisibility,
                RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}},
                Converter={StaticResource _VisibilityToNullableBooleanConverter}}"
            />
    </DataTemplate>
</DataGrid.RowHeaderTemplate>

Converter:

public class VisibilityToNullableBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Visibility)
        {
            return (((Visibility)value) == Visibility.Visible);
        }
        else
        {
            return Binding.DoNothing;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool?)
        {
            return (((bool?)value) == true ? Visibility.Visible : Visibility.Collapsed);
        }
        else if (value is bool)
        {
            return (((bool)value) == true ? Visibility.Visible : Visibility.Collapsed);
        }
        else
        {
            return Binding.DoNothing;
        }
    }
}
Share:
27,799
WillH
Author by

WillH

Updated on February 07, 2020

Comments

  • WillH
    WillH about 4 years

    I am using a WPF Datagrid with a RowDetails panel where the RowDetailsVisibilityMode is set to "VisibleWhenSelected" and the SelectionMode="Extended" so that multiple rows can be selected and hence display RowDetails, as below:

    <dg:DataGrid x:Name="MyGrid"
                 ItemsSource="{Binding Path=MyItems}"
                 AutoGenerateColumns="True"
                 SelectionMode="Extended"
                 RowDetailsVisibilityMode="VisibleWhenSelected">
    
      <dg:DataGrid.RowDetailsTemplate>
        <DataTemplate>
          <TextBlock Text="Further Details..."/>
        </DataTemplate>
      </dg:DataGrid.RowDetailsTemplate>
      ...
    </dg:DataGrid>
    

    Unfortunately, for this application it isn't intuitive to display row details on 'selected' rows, the client would like to click a checkbox on a number of rows to display the RowDetails pane, but also scroll around the grid selecting other rows. In other words fix the rows that display RowDetails no matter what happens on the DataGrid.

    So currently scrolling around closes the RowDetailsPanes that they have opened. What I would like to do is to have a checkbox in one of the columns and bind the RowDetails panel visibility to this property but I can't figure out how to do it. The problem is simply that RowDetailsPane only operates on the row selection(s) in the datagrid - can it be extended somehow to operate on a property of my choosing?

    Thanks in advance, Will

  • WillH
    WillH over 14 years
    Thanks Rory, nice solution. This is exactly what I wanted, I was wrong to think in terms of binding to a property in my ViewModel since this is purely View functionality, so the method operating on the click event of the checkbox is perfect.
  • Michael S. Scherotter
    Michael S. Scherotter over 14 years
    This also works for Silverlight if you set the initial DataGrid.RowDetailsVisibilityMode="Collapsed"
  • Jason Frank
    Jason Frank almost 11 years
    +1 for a Xaml-only approach since it is easier to apply in multiple places and is more portable when moving DataGrid Xaml.
  • user3260977
    user3260977 about 7 years
    This works well when you set the RowDetailsVisibilityMode to Collapsed.