Search code examples
wpfsilverlightxamlsilverlight-toolkitgridsplitter

GridSplitter MinWidth with fixed size


I have a Grid with 2 columns separated by a GridSplitter using the following XAML code :

<Grid>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="100" MinWidth="20" />
    <ColumnDefinition Width="10" />
    <ColumnDefinition Width="*" MinWidth="100" />
    </Grid.ColumnDefinitions>

    <Rectangle Fill="Blue" />
    <GridSplitter Grid.Column="1" Background="LightGray" HorizontalAlignment="Stretch" />
    <Rectangle Fill="Yellow" Grid.Column="2" />
</Grid>

Problem : The MinWidth of the Column on the right is ignored

  • I definitely need the first column Width to be "100px" when page loads, so It cannot be * sized.
  • I do not want to set a MaxWidth on the first column

*I know that has been adressed before but it always suggest to set column size to * or set a maxWidth on the first column... I don't want that.


Found a solution, but its UGLY! :p, anybody has a cleaner way to achieve what I want... CODELESS (if possible)?

private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
   var g = (Grid)sender;

   Double maxW = e.NewSize.Width - g.ColumnDefinitions[2].MinWidth - g.ColumnDefinitions[1].ActualWidth;
   g.ColumnDefinitions[0].MaxWidth = maxW;
}

Solution

  • The basic problem is that a grid splitter works by adjusting the width of the left column only and assumes the right column will star-size to fit the remaining space.

    That means the problem you are trying to solve is actually "how do I limit the max width of the left column so that the right column does not get too small?". This is basically what your code sample is doing.

    If you want a more portable solution, that you can implement in XAML, create a Silverlight behavior that can be applied to a grid (as shown below). It will attach to the parent grid's SizeChanged event and do pretty much exactly what your code snippet does, but being a behavior you can drag and drop them in Blend or attach them in XAML.

    Here is a sample behavior I threw together for you as an example (based on your own code):

    MinWidthSplitterBehavior.cs

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Interactivity;
    
    namespace GridSplitterMinWidth
    {
        public class MinWidthSplitterBehavior : Behavior<Grid>
        {
            public Grid ParentGrid { get; set; }
    
            protected override void OnAttached()
            {
                base.OnAttached();
                ParentGrid = this.AssociatedObject as Grid;
                ParentGrid.SizeChanged += parent_SizeChanged;
            }
    
            void parent_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                if (ParentGrid.ColumnDefinitions.Count == 3)
                {
                    Double maxW = e.NewSize.Width - ParentGrid.ColumnDefinitions[2].MinWidth -
                                  ParentGrid.ColumnDefinitions[1].ActualWidth;
                    ParentGrid.ColumnDefinitions[0].MaxWidth = maxW;
                }
            }
    
            protected override void OnDetaching()
            {
                base.OnDetaching();
                if (ParentGrid != null)
                {
                    ParentGrid.SizeChanged -= parent_SizeChanged;
                }
            }
        }
    }
    

    and use it like this:

    <UserControl x:Class="GridSplitterMinWidthApp.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:GridSplitterMinWidth="clr-namespace:GridSplitterMinWidth"
        xmlns:interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:Controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
    
        <Grid x:Name="LayoutRoot" Background="White">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100" MinWidth="20" />
                    <ColumnDefinition Width="10" />
                    <ColumnDefinition Width="*" MinWidth="100" />
                </Grid.ColumnDefinitions>
                <interactivity:Interaction.Behaviors>
                    <GridSplitterMinWidth:MinWidthSplitterBehavior/>
                </interactivity:Interaction.Behaviors>
                <Rectangle Fill="Blue" />
                <Controls:GridSplitter Grid.Column="1" Background="LightGray" HorizontalAlignment="Stretch">
                </Controls:GridSplitter>
                <Rectangle Fill="Yellow" Grid.Column="2" />
            </Grid>
        </Grid>
    </UserControl>