Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop Gridsplitter stretching content beyond window

Tags:

Given the below XAML, how do I have the gridsplitter respect the MinHeight given to the 3rd row and have the content remain inside my window?

<Grid>     <Grid.RowDefinitions>         <RowDefinition Height="Auto" />         <RowDefinition Height="Auto" />         <RowDefinition MinHeight="40" />     </Grid.RowDefinitions>     <Expander Grid.Row="0" ExpandDirection="Down" VerticalAlignment="Top">         <Grid>             <Grid.RowDefinitions>                 <RowDefinition Height="Auto" MinHeight="40" />                 <RowDefinition Height="*" />             </Grid.RowDefinitions>             <Border Grid.Row="0" MinHeight="100" Background="Black" />             <GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Background="LightBlue" ResizeBehavior="PreviousAndCurrent" />         </Grid>     </Expander>     <Expander Grid.Row="1" ExpandDirection="Down" VerticalAlignment="Top">         <Grid>             <Grid.RowDefinitions>                 <RowDefinition Height="Auto" MinHeight="40" />                 <RowDefinition Height="*" />             </Grid.RowDefinitions>             <Border Grid.Row="0" MinHeight="100" Background="Black" />             <GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Background="LightBlue" ResizeBehavior="PreviousAndCurrent" />         </Grid>     </Expander>     <Border DockPanel.Dock="Bottom"  Grid.Row="2" Background="Lime" MinHeight="30" >         <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=DockPanel},Path=ActualHeight,StringFormat={}{0:f0}}" />     </Border> </Grid> 
like image 830
DaveO Avatar asked May 04 '11 06:05

DaveO


2 Answers

The way your code is, this cannot be done mate. This is due to how the GridSplitter works.

A few points

  • A GridSplitter will always work on directly adjacent rows/columns
  • In reality, your MinHeight IS being respected, but so is the GridSplitter's request to grow being respected, which results in the Grid growing larger than your Window
  • When sized to Auto, a row/column will always resize according to its content, not bigger, and not smaller
  • Therefore if a GridSplitter is sandwiched between two * sized rows/columns, then it would implicitly respect your MinHeight, since in reality, it would not be touching it

You have a few solutions

  1. Add another row in the 3rd position which is * sized, and have your border on row 3 with a RowSpan of 2 (so the 3rd row is the one being really resized, and your 4th row isn't touched. Though this will also have side-effects.
  2. Handle a mixture of DragEnter and PreviewMouseMove events on the GridSplitter, keeping track of focus, and cancelling (e.Handled = true) the event when a certain size is reached.

This is what I can think of mate, hope I've been of some help.

like image 142
Stefan Z Camilleri Avatar answered Nov 29 '22 01:11

Stefan Z Camilleri


I created a custom grid splitter class that will not allow the grid splitter to go off the edge of a window (either the bottom or the side).

Public Class CustomGridSplitter Inherits GridSplitter  Public Enum SplitterDirectionEnum     Horizontal     Vertical End Enum  Public Property SplitterDirection As SplitterDirectionEnum Public Property MinimumDistanceFromEdge As Integer  Private _originPoint As Point  Private Sub customSplitter_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles MyBase.MouseDown     _originPoint = e.GetPosition(Window.GetWindow(Me)) End Sub  Private Sub customSplitter_PreviewMouseMove(sender As Object, e As MouseEventArgs) Handles MyBase.PreviewMouseMove      If e.LeftButton = MouseButtonState.Pressed Then         Dim pwindow As Window = Window.GetWindow(Me)         Dim newPoint As Point = e.GetPosition(pwindow)          If SplitterDirection = SplitterDirectionEnum.Horizontal Then             If newPoint.Y >= _originPoint.Y Then                 If newPoint.Y >= pwindow.ActualHeight - MinimumDistanceFromEdge Then                     e.Handled = True                 End If             Else                 If newPoint.Y > pwindow.ActualHeight - (MinimumDistanceFromEdge + 2) Then                     e.Handled = True                 End If             End If         Else             If newPoint.X >= _originPoint.X Then                 If newPoint.X >= pwindow.ActualWidth - MinimumDistanceFromEdge Then                     e.Handled = True                 End If             Else                 If newPoint.X > pwindow.ActualWidth - (MinimumDistanceFromEdge + 2) Then                     e.Handled = True                 End If             End If         End If           _originPoint = newPoint     End If End Sub 

End Class

To use it in XAML:

<CustomGridSplitter SplitterDirection="Vertical" MinimumDistanceFromEdge="100" x:Name="splitterCenter" ResizeDirection="Columns" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Stretch" Width="2" Margin="2,0,2,0"/> 

The custom properties to set are the "SplitterDirection" and "MinimumDistanceFromEdge". Everything works like the base grid splitter.

This uses mouse events to determine where in the window the user is dragging the splitter and handles the events if they get too close to the edge.

like image 32
nicko Avatar answered Nov 29 '22 03:11

nicko