Monday, December 30, 2013

Toggling ALL datagrid detail visibility

WPF Version 4.0

My previous post explained how to use a toggle button to allow the user to toggle the details of datagrid rows individually. My users also want a single toggle button that will display or hide the details of all the datagrid rows. I started by sniffing around the Visual Tree to find all the DataGridRows and toggling their visibility but this has two problems.

If the datagrid's EnableRowVirtualization property is true (the default) then the VisualTree only includes rows that are currently displayed. If the property is false then the VisualTree will return all rows but it's very slow. I did put together some handy code for finding all children of a specific type which I have included but didn't use for this solution.


private void GetChildren(DependencyObject Parent, System.Type ChildType, List Children)
{
    int iCount = VisualTreeHelper.GetChildrenCount(Parent);
    for (int i = 0; i < iCount; i++)
    {
        DependencyObject Child = VisualTreeHelper.GetChild(Parent, i);
        if (Child.GetType() == ChildType) Children.Add(Child);
        GetChildren(Child, ChildType, Children);
    }
}

You call it like this (assuming dg is a datagrid and you want to find all its datagridrows). It places all the DataGridRow descendants of dg into the list called l.

   List<DependencyObject> l = new List<DependencyObject>();
   GetChildren(dg, typeof(DataGridRow), l);

I accidentally came across a very useful grid method called SetDetailsVisibilityForItem. There's also a Clear and Get version of this method. To hide all details for a grid, even when they're not displayed and the grid is virtualized, you just iterate through the grid's ItemsSource and call this method for each item. I created a toggle button called tb and created a Click event handler for it which looks like this.

private void tb_Click(object sender, RoutedEventArgs e)
{
    foreach (DataRowView Item in ((DataView)dg.ItemsSource))
        if (tb.IsChecked.Value)
            dg.SetDetailsVisibilityForItem(Item, Visibility.Visible);
        else
            dg.SetDetailsVisibilityForItem(Item, Visibility.Collapsed);
}

This solution is simple and quick.

No comments:

Post a Comment