Search code examples
c#wpf.net-core.net-8.0

Need WPF GridSplitter that can automatically resize to zero


I want to make a custom GridSplitter that combines a regular splitter behaviour plus a feature - when the splitter resizes automatically one of the areas to zero.

So normal usage is:

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="0.5*" Name="A"/>
    <ColumnDefinition Width="Auto"/>
    <ColumnDefinition Width="0.5*" Name="B"/>
  </Grid.ColumnDefinitions>
  
  <GridSplitter Grid.Column="1"... />

initially - both columns A and B have same size = 50% of available width. User can drag the splitter to change their widths. Now I want user to be able to double click on the splitter (or any other way to initiate the action) - and the column A resized to 0 and B to 100%, if acted again - then A to 100% and B to 0.

Obviously I can do it in the parent by setting column widths in code behind. But I want to reuse this functionality in other parts and make it as simple to use as possible.


Solution

  • The best way to achieve this is to create your own GridSplitter or add a behavior to it using an attached property.

    Here I provide a custom implementation of GridSplitter by inheriting of it.
    To move the splitter I use a GridSplitterAutomationPeer:

    public class MyGridSplitter : GridSplitter
    {
        private readonly ITransformProvider _automationPeer;
    
        public MyGridSplitter()
        {
            _automationPeer = new GridSplitterAutomationPeer(this);
        }
    
        protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
        {
            base.OnMouseDoubleClick(e);
    
            var prtp = GetPositionRelativeToParent();
            if (prtp.X is 0)
            {
                _automationPeer.Move(double.MaxValue, double.MaxValue);
            }
            else
            {
                _automationPeer.Move(-double.MaxValue, -double.MaxValue);
            }
        }
    
        private Point GetPositionRelativeToParent()
        {
            return TranslatePoint(new Point(0, 0), VisualTreeHelper.GetParent(this) as UIElement);
        }
    }
    

    You use it like this:

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="3" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
    
        <Label Grid.Column="0" Content="LEFT" HorizontalAlignment="Center" VerticalAlignment="Center" />
        <local:MyGridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
        <Label Grid.Column="2" Content="RIGHT" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
    

    Note: only the left-right behavior is tested.
    Working code available here.