Stop Gridsplitter stretching content beyond window - wpf

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>

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
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.
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.

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.

I found another solution to this problem, though in a much more simple case where I just had two columns inside a window that I wanted to resize.
The solution that I came up with (described in more detail here: https://stackoverflow.com/a/46924893/6481970) was to add event callbacks for when the grid was resized, when the GridSplitter moved, and when the window was resized (to handle the case where you resize the window to no longer fit the content because the grid doesn't automatically resize itself to fit the smaller window).
Here is some simplified code:
XAML:
<Grid x:Name="ResizeGrid" SizeChanged="ResizeGrid_SizeChanged">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="C0" Width="150" MinWidth="50" />
<ColumnDefinition Width="5" />
<ColumnDefinition x:Name="C2" Width="*" MinWidth="50" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Background="Green" />
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" DragCompleted="GridSplitter_DragCompleted" />
<Grid Grid.Column="2" Background="Red" />
</Grid>
C# Code Behind:
C0.MaxWidth = Math.Min(ResizeGrid.ActualWidth, ActualWidth) - (C2.MinWidth + 5);

Related

WPF ScrollViewer gives my listview (in a grid row) the whole screen instead of a portion

The main grid on my usercontrol has 3 rows. The top row is a data-bound listvew that takes about 60% of the whole window (there's more data rows than can be displayed and the listview automatically displays a scroll bar - This is good). Second row is a gridsplitter and the 3rd takes up the rest of the display.
This 3rd row has a grid wrapped in a border and also contains a textbox that wraps & can grow larger. When it does, it sometimes pushes the buttons at the very bottom off the screen, so I thought that if I wrapped a ScrollViewer around the main grid that I'd keep my 3 rows on the screen in the same proportion with the existing listview scrollbar left intact and then just get an additional scrollbar on the right that would let me scroll down to see the buttons if the 3rd row grew too tall (like you do on this browser page with scroll bars for the code & the page scroller too.
What happens instead, is that the first row with the listview has expanded vertically to take the whole screen and I can't see rows 2 or 3 at all until I've scrolled to the end of all the items in the listview. I've tried various combinations of hardcoding row heights (bad, I know) 'Auto' & '*' to now avail.
Is there a way to accomplish what I'm trying? I didn't think I'd have to (and down't want to) re-engineer the whole screen for this.
Thanks, I'm new to WPF & it's fun but very frustrating at times!
I'm posting some XAML, below, but I'm not sure it will help.
<ScrollViewer>
<Grid Name="grdEvents" HorizontalAlignment="Center" >
<Grid.RowDefinitions>
<RowDefinition Height="60*" />
<RowDefinition Height="10" />
<RowDefinition Height="30*"/>
</Grid.RowDefinitions>
<ListView SelectionChanged="lvActivities_SelectionChanged" MouseDoubleClick="ListView_MouseDoubleClick" Grid.Row="0" Name="lvActivities" HorizontalAlignment="Stretch" LVLO:ListViewLayoutManager.Enabled="True" >
<!--ItemContainerStyle="{StaticResource SelectedItem}" MouseEnter="lvActivities_MouseEnter" -->
<ListView.ItemContainerStyle>
<Style TargetType="ListBoxItem">
...
</ListView>
<GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch"> </GridSplitter>
<Border Grid.Row="2" CornerRadius="20"
BorderBrush="Gray"
Background="White"
BorderThickness="2"
Padding="8">
<Grid Name="wpCurrentRow" DataContext="{Binding ElementName=lvActivities, Path=SelectedItem}" Grid.Row="2" Background="{StaticResource ResourceKey=MyBackGroundBrush}">
I don't think you can accomplish what you want with relative row sizes. What you can do, however, is manually set a proportional height to the top row any time the ScrollViewer's size changes. But since you also have a splitter, you will want to stop doing this once the user adjusts the height manually. Take a look at this:
XAML:
<Window x:Class="StackOverflow.Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ScrollViewer x:Name="_scrollViewer">
<Grid>
<Grid.RowDefinitions>
<RowDefinition x:Name="_mainRow" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListView />
<GridSplitter x:Name="_splitter"
Grid.Row="1"
Height="5"
HorizontalAlignment="Stretch"
ResizeDirection="Rows"
ResizeBehavior="PreviousAndNext"
MouseDoubleClick="OnSplitterMouseDoubleClick" />
<Grid Grid.Row="2" />
</Grid>
</ScrollViewer>
</Grid>
</Window>
Code behind:
public partial class MainWindow
{
private bool _shouldUpdateGridLayout;
public MainWindow()
{
InitializeComponent();
EnsureGridLayoutUpdates();
}
private void EnsureGridLayoutUpdates()
{
if (_shouldUpdateGridLayout)
return;
_scrollViewer.SizeChanged += OnScrollViewerSizeChanged;
_splitter.DragCompleted += OnSplitterDragCompleted;
_shouldUpdateGridLayout = true;
}
private void CancelGridLayoutUpdates()
{
if (!_shouldUpdateGridLayout)
return;
_scrollViewer.SizeChanged -= OnScrollViewerSizeChanged;
_splitter.DragCompleted -= OnSplitterDragCompleted;
_shouldUpdateGridLayout = false;
}
private void UpdateGridLayout()
{
_mainRow.Height = new GridLength(2 * _scrollViewer.ActualHeight / 3);
}
private void OnScrollViewerSizeChanged(object s, SizeChangedEventArgs e)
{
UpdateGridLayout();
}
private void OnSplitterDragCompleted(object s, DragCompletedEventArgs e)
{
CancelGridLayoutUpdates();
}
private void OnSplitterMouseDoubleClick(object s, MouseButtonEventArgs e)
{
EnsureGridLayoutUpdates();
UpdateGridLayout();
// Handle the event to prevent DragCompleted from being raised
// in response to the double-click.
e.Handled = true;
}
}
Note that I chose to restore both the default size and automatic size management when the user double-clicks the splitter. It's not the prettiest solution, but it beats using fixed heights. Feel free to encapsulate the behavior in custom panel/control.
Instead of using proportions, use hardcoded heights on the rows. Change the 60* to 60 for the first row.
Also just for the sake of experimentation you could try this:
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListBox Name="ListBox1" HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100" Grid.Row="0" Background="Blue"/>
<ScrollViewer Grid.Row="1">
<StackPanel >
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Click="Button_Click" />
<TextBox>Hello </TextBox>
</StackPanel>
</ScrollViewer>
It adds a scroll viewer just to the second row and you then use a stack panel to store the rest of the elements. It makes it look a bit better imo too.
The elements were just added for example; replace them with your own.

WPF GridSplitter behavior when resizing its parent Window

I have defined my GridSplittler XAML like the following.
<Window>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<Border Grid.Column="0" Background="Red" />
<GridSplitter Grid.Column="1" ResizeDirection="Columns" Width="3" Height="Auto" HorizontalAlighment="Stretch" VerticalAlignment="Stretch" />
<Border Grid.Column="0" Background="Green" />
</Window>
This will create two columns with a grid splitter between them and it will correctly resize the columns as the grid splitter is dragged left and right. Now if you resize the whole Window I would like the width of left red column to remain fixed and have the width of the right green column change (as the Window is resized). Its the same effect as when you resize the whole Visual Studio application and the Solution Explorer width remains fixed but the width of a code tab changes. Also the same as the SQL Server Management Studio; the Object Explorer width remains fixed but the SQL tabs width changes. I realize that these two examples use a more complicated docking control but I was hoping to achieve the same result with using the WPF GridSplitter.
Edit: Based on mathieu suggestions all the was necessary was to give the first column definition an initial width (shown using 200 below).
<Grid Name="GridName">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="Red" />
<GridSplitter Name="SplitterName" Grid.Column="1" ResizeDirection="Columns" Width="3" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Border Grid.Column="2" Background="Green" />
</Grid>
Now when the Window is re-sized it only changes the width of the green border and the width of the red border remains fixed. Thanks!
If you don't mind some code behind, you can achieve this behaviour by reacting to the DragDelta event of the splitter, and adjusting the width of the first column, by removing the Star width, and fixing the width according to the drag delta.
Xaml :
<Grid Name="GridName">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="Red" />
<GridSplitter Name="SplitterName" Grid.Column="1" ResizeDirection="Columns" Width="3" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Border Grid.Column="2" Background="Green" />
</Grid>
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
SplitterName.DragDelta += SplitterNameDragDelta;
}
private void SplitterNameDragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
GridName.ColumnDefinitions[0].Width = new GridLength(GridName.ColumnDefinitions[0].ActualWidth + e.HorizontalChange);
}
}
I've used the snipet of mathieu - and modified it for code behind use.
In my case I need a dynamic number of Items resized by the GridSplitter.
I used the Thumb Control to have full control of the action
private Thumb GetNewThumbAsGridSplitter(int column)
{
var gs = new Thumb();
gs.SetValue(Grid.ColumnProperty, column);
// gs.SetValue(Grid.RowSpanProperty, 2);
// gs.SetValue(Grid.RowProperty, 1);
gs.Width = 5;
gs.MouseEnter += (o, i) =>
{
Mouse.OverrideCursor = Cursors.ScrollWE;
};
gs.MouseLeave += (o, i) =>
{
Mouse.OverrideCursor = Cursors.Arrow;
};
gs.DragDelta += (o, i) =>
{
var grid = (Grid)gs.Parent;
var previous = (YourControl)((grid.Children[column - 1]));
var next = (YourControl)(grid.Children[column + 1]);
if (next.MinWidth >= (next.ActualWidth - i.HorizontalChange))
{
return;
}
if (previous.MinWidth >= (previous.ActualWidth + i.HorizontalChange))
{
return;
}
previous.Width = previous.ActualWidth + i.HorizontalChange;
next.Width = next.ActualWidth - i.HorizontalChange;
};
return gs;
}

How to bind Font Size to variable Grid Size

I have a grid with 2 columns and 2 rows. A single character (Unicode U+2699) was placed inside the bottom right grid field. It looks like this:
I´d like the character to automatically adjust its font size to fit the grid field it has been placed in (in this case it should be bound to the height of the second grid row, but since in some cases it could be unclear if the height or the width of the grid is smaller, it would be also nice to know how to bind to the lowest of those 2 values).
My implementation so far is something like the following (I simplified it a bit for this example):
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition x:Name="heightToBind" Height="40"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="14*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button FontSize="{Binding ElementName=heightToBind, Path=Height.Value, Mode=OneWay}" Content="⚙" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" />
</Grid>
The problem here is, that it only works if the height is a fixed value inside the RowDefinitions. I want it to work with the following definition:
<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition x:Name="heightToBind" Height="*"/>
</Grid.RowDefinitions>
As a bonus question I´d also be interested why it might be that the character is placed too low so it is getting cut off at the bottom (I tried VerticalAlignment="Center" for the button but with no effect).
You can try using a ViewBox as the button's content:
<Button Grid.Row="1" Grid.Column="1">
<Button.Content>
<Viewbox StretchDirection="Both" HorizontalAlignment="Stretch">
<TextBlock Text="⚙" />
</Viewbox>
</Button.Content>
</Button>
A ViewBox can stretch and scale his child to fill all the available space...
You could try binding to the ActualHeight instead of the Height:
<Button FontSize="{Binding ElementName=heightToBind, Path=ActualHeight.Value, Mode=OneWay}"
Content="⚙" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" />
This should work.
The * on the grid definition means take the available space as the height so it's only determined when the page layout has been prepared for layout. If the height is either unset or changed then the real height is returned in the ActualHeight property.

Vertically expand textbox automatically when text is too long

I am trying to mimic the Sticky Notes application in Windows 7. In the original application, if you type text into a Sticky Note and the text becomes too large (vertically, as in number of lines) to fit in the window, the window automatically expands vertically, one line at a time, to allow for more room. In other words, where in a normal Textbox a vertical scrollbar would appear and the text would scroll down (so that the first line becomes invisible), in the Sticky Notes the textbox expands exactly enough to fit the text so that no scrollbar appears. The scrollbar still appears when you manually resize the window afterwards, of course.
If you have Windows 7 just open the Sticky Notes application and type a few lines in the sticky note until it enlarges.
I am trying to mimic this effect but I'm having no luck. The problem seems that the actual Window should resize, not just the Textbox (I don't think WPF works this way, that a resize of a child element can 'force' the parent element to become larger? At least not for a Window, right?).
The contents of the Window at this point are such:
<Window Background="Transparent" BorderBrush="Transparent">
<!-- Transparent border to draw dropshadow on -->
<Border Background="Transparent" BorderBrush="Transparent">
<!-- Grid with UI elements -->
<Grid Margin="5" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="27" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Stickynote header -->
<Border ... />
<!-- Content -->
<Border Grid.Row="1">
<TextBox Text="{Binding ContentText}" ... />
</Border>
</Grid>
</Border>
</Window>
Does anybody know how I can achieve this effect? Thanks!
Try the Window Property SizeToContent="Height"
Sample
<Window ...
MaxHeight="500"
SizeToContent="Height">
<Border Background="Transparent" BorderBrush="Transparent">
<Grid Margin="5" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="27" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="1">
<TextBox AcceptsReturn="True" MinHeight="100"/>
</Border>
</Grid>
</Border>
</Window>
Edit
To use it with the TransparentWindow you posted, add transparentWindow.SizeToContent = SizeToContent.Manual in OnDragDelta (TransparentWindow.cs)
private static void OnDragDelta(object sender, DragDeltaEventArgs e)
{
TransparentWindow transparentWindow = (TransparentWindow)sender;
Thumb thumb = e.OriginalSource as Thumb;
transparentWindow.SizeToContent = SizeToContent.Manual;
if (thumb != null && transparentWindow.WindowState == WindowState.Normal)
{
//...
}
}

GridSplitter with min constraints

I want a Grid layout with two rows and splitter between them. Rows should have a minimum height of 80 pixels.
This code works great:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" MinHeight="80" />
<RowDefinition Height="5" />
<RowDefinition Height="*" MinHeight="80" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<TextBlock Grid.Row="2" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
</Grid>
But I want top row to have an Auto height until user manually change it using the splitter. So I changed the code to this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="80" />
<RowDefinition Height="5" />
<RowDefinition Height="*" MinHeight="80" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<TextBlock Grid.Row="2" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
</Grid>
And there is a problem. Splitter still satisfies row constraints, but it begins to increase top row's height infinitely if I drag splitter too low. This results in bottom row to be completely below window's bottom border.
I have done some Reflector on GridSplitter code and see that it uses different logic if rows has Auto or Star height.
Any suggestions how can I "fix" it?
I've run into this problem a few times myself. It appears as though the GridSplitter doesn't play well with Auto. That said, I have found a potential workaround.
You are able to specify the value of a GridLength object using "star coefficients". This acts as a multiplier for the length in question.
In your example, if you take the row you want to remain as star, and set the the star coefficient to a really large number, the row will take up all available space (forcing the other row to become its min-height). While this isn't the same behavior as "auto" (the height of the first row is not determined by its contents height), it might get you closer.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" MinHeight="80" />
<RowDefinition Height="5" />
<RowDefinition Height="10000*" MinHeight="80" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
<GridSplitter Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
<TextBlock Grid.Row="2" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
</Grid>
I have developed a workaround for this problem. Point is to set MaxHeight for the top row while we are dragging splitter. Here the code:
public class FixedGridSplitter : GridSplitter
{
private Grid grid;
private RowDefinition definition1;
private double savedMaxLength;
#region static
static FixedGridSplitter()
{
new GridSplitter();
EventManager.RegisterClassHandler(typeof(FixedGridSplitter), Thumb.DragCompletedEvent, new DragCompletedEventHandler(FixedGridSplitter.OnDragCompleted));
EventManager.RegisterClassHandler(typeof(FixedGridSplitter), Thumb.DragStartedEvent, new DragStartedEventHandler(FixedGridSplitter.OnDragStarted));
}
private static void OnDragStarted(object sender, DragStartedEventArgs e)
{
FixedGridSplitter splitter = (FixedGridSplitter)sender;
splitter.OnDragStarted(e);
}
private static void OnDragCompleted(object sender, DragCompletedEventArgs e)
{
FixedGridSplitter splitter = (FixedGridSplitter)sender;
splitter.OnDragCompleted(e);
}
#endregion
private void OnDragStarted(DragStartedEventArgs sender)
{
grid = Parent as Grid;
if (grid == null)
return;
int splitterIndex = (int)GetValue(Grid.RowProperty);
definition1 = grid.RowDefinitions[splitterIndex - 1];
RowDefinition definition2 = grid.RowDefinitions[splitterIndex + 1];
savedMaxLength = definition1.MaxHeight;
double maxHeight = definition1.ActualHeight + definition2.ActualHeight - definition2.MinHeight;
definition1.MaxHeight = maxHeight;
}
private void OnDragCompleted(DragCompletedEventArgs sender)
{
definition1.MaxHeight = savedMaxLength;
grid = null;
definition1 = null;
}
}
Then just replace GridSplitter with FixedGridSplitter.
Note: this code is not general - it doesn't support columns and assume that bottom row has MinHeight specified.

Resources