Search code examples
c#wpfwpfdatagridmaster-detail

Collapsing the details row in a data grid


I have a data grid with a details row, something like:

<DataGrid x:Name="Applications" CanUserResizeColumns="False" CanUserResizeRows="False" RowStyle="{StaticResource CollapsedRow}" AutoGenerateColumns="false" CanUserAddRows="false" ItemsSource="{Binding Applications}">

<DataGrid.Columns>
 <DataGridTemplateColumn>
   <DataGridTemplateColumn.CellTemplate>
     <DataTemplate>
       <Button Content='&#709;' FontSize="9" Name="ExpanderButton" Click="OnGroupChange" />
     </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
   </DataGridTemplateColumn>
  <DataGridTextColumn Width="181" Header="Application name" Binding="{Binding Name, Mode=OneWay}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
    <!-- SOME DETAILS HERE -->
</DataGrid.RowDetailsTemplate>
</DataGrid>

Now the idea is that I have a data grid with additional columns with a button that will expand the details row, so my code behind is:

private void OnGroupChange(object sender, RoutedEventArgs e)
{
    CollapseGroupDetails();
    for (var visible = (Visual)sender; visible != null; visible = VisualTreeHelper.GetParent(visible) as Visual)
    {
        if (visible.GetType() != typeof(DataGridRow))
            continue;

        var row = (DataGridRow)visible;
        var appName = (ExtenedApplicationFile)row.Item;
                ((ApplicationsViewModel)DataContext).SelectedApplicationFile = appName;

        row.DetailsVisibility = row.DetailsVisibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
    }

    Applications.UpdateLayout();
}

private void CollapseGroupDetails()
{
    foreach (object item in Applications.ItemsSource)
    {
        if (!(Applications.ItemContainerGenerator.ContainerFromItem(item) is DataGridRow row) ||  row.DetailsVisibility != Visibility.Visible)
            continue;

        row.DetailsVisibility = Visibility.Collapsed;
        break;
    }
}

So it works like: I click on a button, it expands the details row of the selected grid row and closes the others, but the problem is when I click on the button on an open row I want it to collapse, but

row.DetailsVisibility = row.DetailsVisibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;

Value of this property is already collapsed and it sets the property to visible again, but when I remove:

CollapseGroupDetails();

method it works, but if I click on the other row's button, the previously selected details row stays open. I have checked if I select a proper row but checking its index and it is correct. Is there a way to combine that?


Solution

  • You could create a temporary copy of the Visibility value before you set the property:

    private void OnGroupChange(object sender, RoutedEventArgs e)
    {
        DataGridRow row = null;
        for (var visible = (Visual)sender; visible != null; visible = VisualTreeHelper.GetParent(visible) as Visual)
        {
            if (visible.GetType() != typeof(DataGridRow))
                continue;
    
            row = (DataGridRow)visible;
            var appName = (ExtenedApplicationFile)row.Item;
            ((ApplicationsViewModel)DataContext).SelectedApplicationFile = appName;
    
            break;
        }
    
        if (row != null)
        {
            Visibility currentVisibility = row.DetailsVisibility;
            CollapseGroupDetails();
            row.DetailsVisibility = currentVisibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
        }
        else
        {
            CollapseGroupDetails();
        }
    
        Applications.UpdateLayout();
    }