13
votes

I ran into a strange issue...
It looks like resizing Grid's columns using a GridSplitter disables (or otherwise deactivates) the trigger defined on a Grid's column.

Here's my setup:

A Grid has 3 columns, defined as follows:

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition>
        <ColumnDefinition.Style>
            <Style>
                <Setter Property="ColumnDefinition.Width" Value="Auto"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=OpenItemViewModels.Count}" Value="0">
                        <Setter Property="ColumnDefinition.Width" Value="0"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ColumnDefinition.Style>
    </ColumnDefinition>
    <ColumnDefinition>
        <ColumnDefinition.Style>
            <Style>
                <Setter Property="ColumnDefinition.Width" Value="4*"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=OpenItemViewModels.Count}" Value="0">
                        <Setter Property="ColumnDefinition.Width" Value="0"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ColumnDefinition.Style>
    </ColumnDefinition>
</Grid.ColumnDefinitions>

The expectation is that when there are no items that constitute ItemsSource for the control in the third column, 0 width will be assigned to the second and third columns (hosting the GridSplitter and the auxiliary items control, respectively).

This works well as long as I don't touch the Splitter (when all the tabs in the auxiliary control are closed, only the first column remains visible).
The problems start if I move the splitter, thus effectively changing the proportion between columns ##0 and 2. In such scenario, these columns' width is not reset when all the items in the right-hand control are closed.

I suspect this has something to do with the GridSplitter "overruling" my definitions in XAML.

Can someone please confirm / disprove this theory, and suggest how to work around the problem?

3

3 Answers

20
votes

I had the same problem for rowdefinition. Gridsplitter will override whatever we give in style or setters. It can be solved using animation (since animation has the highest priority in dependency property value resolution). Do the same for the third column.

<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition>
    <ColumnDefinition.Style>
        <Style>
            <Setter Property="ColumnDefinition.Width" Value="Auto" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=OpenItemViewModels.Count}" Value="0">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard Name="BeginStoryboard1">
                            <Storyboard>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Width">
                                    <ObjectAnimationUsingKeyFrames.KeyFrames>
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0"
                                                                Value="{x:Static GridLength.Auto}" />
                                    </ObjectAnimationUsingKeyFrames.KeyFrames>
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                    <DataTrigger.ExitActions>
                        <RemoveStoryboard BeginStoryboardName="BeginStoryboard1" />
                    </DataTrigger.ExitActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ColumnDefinition.Style>
</ColumnDefinition>

3
votes

I came up with a helper class that helps solve the problem of collapsible columns/rows that are also resized with GridSplitter.

public class CollapsibleRowDefinition : RowDefinition
{
    public static readonly DependencyProperty IsCollapsedProperty = DependencyProperty.Register(
        "IsCollapsed",
        typeof(bool),
        typeof(CollapsibleRowDefinition),
        new FrameworkPropertyMetadata(
            false,
            (s,e) => { ((CollapsibleRowDefinition) s).IsCollapsed = (bool)e.NewValue; }));

    private bool isCollapsed = false;

    public CollapsibleRowDefinition()
    {
        DependencyPropertyDescriptor.FromProperty(RowDefinition.HeightProperty, typeof(RowDefinition)).AddValueChanged(this,
            (sender, args) =>
            {
                if (!this.IsCollapsed)
                {
                    this.ExpandedHeight = this.Height;
                }
            });
    }

    public GridLength CollapsedHeight { get; set; }
    public GridLength ExpandedHeight { get; set; }

    public bool IsCollapsed
    {
        get { return this.isCollapsed; }
        set
        {
            if (this.isCollapsed != value)
            {
                this.isCollapsed = value;
                this.Height = value ? this.CollapsedHeight : this.ExpandedHeight;
            }
        }
    }
}

markup then goes like this

        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition Height="2*"/>
            <RowDefinition Height="5"/>
            <c:CollapsibleRowDefinition CollapsedHeight="20" ExpandedHeight="*" IsCollapsed="{Binding ElementName=Btn_BottomCollapse, Path=IsChecked}"/>
        </Grid.RowDefinitions>
        <GridSplitter Grid.Row="2" HorizontalAlignment="Stretch"
                      IsEnabled="{Binding ElementName=Btn_BottomCollapse, Path=IsChecked}"/>
0
votes

I had the same problem...

The only thing I was able to work out was something like this:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" x:Name="theColumn"/>
        <ColumnDefinition Width="1*"/>
    </Grid.ColumnDefinitions>
    <Expander Grid.Column="0" x:Name="theExpander" Expander.Collapsed="theExpander_Collapsed">
        ...
    </Expander>
    <GridSplitter Grid.Column="0" HorizontalAlignment="Right" Width="5">
        <GridSplitter.Style>
            <Style TargetType="{x:Type GridSplitter}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=theExpander, Path=IsExpanded}" Value="False">
                        <Setter Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </GridSplitter.Style>
    </GridSplitter>
    <Grid Grid.Column="1">
        ...    
    </Grid>
</Grid>

And the code behind:

    private void theExpander_Collapsed(object sender, RoutedEventArgs e)
    {
        theColumn.Width = GridLength.Auto;
    }

It's not the way I would prefer to do this, but trying to use a style trigger on the column definition just does not work.