GridSplitter overrides ColumnDefinition's style trigger?
Asked Answered
J

4

15

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?

Juncaceous answered 17/12, 2011 at 22:42 Comment(0)
U
22

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>

Ultann answered 16/11, 2012 at 9:11 Comment(1)
Amazing solution. I was struggling 2 days to solve a similar thing, and using this solution it took me an hour to adapt my xaml, only with Rows. Thank you very much!Saphra
S
4

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}"/>
Subcontract answered 10/11, 2015 at 21:59 Comment(1)
Excellent solution... works for me. Here is my version of this solution including an implementation for the ColumnDefinition. Note, I reversed the boolean logic (IsExpanded rather than IsCollapsed). gist.github.com/brinko99/5e7121740b7042604ad47d98750e2961Scrophulariaceous
S
2

I took Terrence's solution (comment in Ghostriders answer) and fixed a little problem that the default values were sometimes not correctly applied.

The source can be found here: https://gist.github.com/medarion/5ff6d04be5630748e8bf92006d0b4472

Usage is unchanged:

<Grid.ColumnDefinitions>
    <controls:CollapsibleColumnDefinition 
        CollapsedWidth="0" ExpandedWidth="500" IsExpanded="{Binding HeaderVisible}"/>
    <ColumnDefinition Width="Auto"/>
    <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
Secondrate answered 14/9, 2022 at 6:27 Comment(0)
C
0

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.

Cataldo answered 24/3, 2012 at 15:36 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.