Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expand/Collapse button in a Silverlight DataGrid

I am using a RowDetailsTemplate in a Silverlight DataGrid to show row details. Setting RowDetailsVisibilityMode="VisibleWhenSelected" does not give a good user experience (only one row can be expanded at a time, all rows cannot be collapsed). What's the easiest way to add an expand/collapse button on each row so that the rows can be expanded/collapsed independently?

like image 617
Naresh Avatar asked Oct 12 '22 14:10

Naresh


1 Answers

I've been meaning to blog my solution to this. I set the grid RowDetailsVisibilityMode to Collapsed and use a DataGridTemplateColumn with a styled ToggleButton in it to toggle the row visibility.

The toggle button can be wired up to toggle the row visibility using either binding or through a TriggerAction.
Binding has to be done in code-behind since you are trying to bind ToggleButton.IsChecked to an element that is generated and does not exist in XAML (DataGridRow.DetailsVisibility) (This will be allowed in SL5 with a stronger RelativeSource binding)

For both solutions I have this extension method in a helper class:

    /// <summary>
    /// Walk up the VisualTree, returning first parent object of the type supplied as type parameter
    /// </summary>
    public static T FindAncestor<T>(this DependencyObject obj) where T : DependencyObject
    {
        while (obj != null)
        {
            T o = obj as T;
            if (o != null)
                return o;

            obj = VisualTreeHelper.GetParent(obj);
        }
        return null;
    }

For code-behind binding method:

    private void ToggleButton_Loaded(object sender, RoutedEventArgs e)
    {
        ToggleButton button = sender as ToggleButton;
        DataGridRow row = button.FindAncestor<DataGridRow>();  //Custom Extension
        row.SetBinding(DataGridRow.DetailsVisibilityProperty, new Binding() 
        {   
            Source = button, 
            Path = new PropertyPath("IsChecked"), 
            Converter = new VisibilityConverter(), 
            Mode = BindingMode.TwoWay 
        });
    }

For TriggerAction method:

public class ExpandRowAction : TriggerAction<ToggleButton>
{
    protected override void Invoke(object o)
    {
        var row = this.AssociatedObject.FindAncestor<DataGridRow>();
        if (row != null)
        {
            if (this.AssociatedObject.IsChecked == true)
                row.DetailsVisibility = Visibility.Visible;
            else
                row.DetailsVisibility = Visibility.Collapsed;
        }
    }
}

Then in XAML:

<sdk:DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <ToggleButton Style="{StaticResource PlusMinusToggleButtonStyle}" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <behaviors:ExpandRowAction/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ToggleButton>
    </DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
like image 105
foson Avatar answered Oct 18 '22 01:10

foson