WPF: collapse GridSplitter?

I have a WPF page with a grid.

There are three lines. Line 0 contains a GridView with Height="*" . Line 1 contains a GridSplitter with Height="auto" . Line 2 contains the data form with Height="2*" .

Here's the thing - I have a button that should switch the visibility of the shape of the part. And it works great. Except that it just hides the form in line 2, it does not expand the grid in line 0 to fill in the blank. I want the button to toggle the GridView on line 0 to take up all the space, and then switch back to where it was.

Obviously, a game with form visibility inside the line will not do what I want.

But what do I need to play with?

+6
source share
3 answers

I had to introduce the Attached Dependency property to handle this in my own application:

 <Grid c:GridSplitterController.Watch="{Binding ElementName=GS_DetailsView}"> <Grid.RowDefinitions> <RowDefinition Height="1*" /> <RowDefinition Height="200" /> </Grid.RowDefinitions> <SomeControl Grid.Row="0" /> <GridSplitter x:Name="GS_DetailsView" Height="4" Grid.Row="1" VerticalAlignment="Top" HorizontalAlignment="Stretch" ResizeBehavior="PreviousAndCurrent" ResizeDirection="Rows" Visibility="{Binding ShowDetails, Converter={StaticResource boolvis}}" /> <OtherControl Grid.Row="1" Margin="0,4,0,0" Visibility="{Binding ShowDetails, Converter={StaticResource boolvis}}" /> </Grid> 

First, define a suitable attached property on DependencyObject :

 public static GridSplitter GetWatch(DependencyObject obj) { return (GridSplitter)obj.GetValue(WatchProperty); } public static void SetWatch(DependencyObject obj, GridSplitter value) { obj.SetValue(WatchProperty, value); } public static readonly DependencyProperty WatchProperty = DependencyProperty.RegisterAttached( "Watch", typeof(GridSplitter), typeof(DependencyObject), new UIPropertyMetadata(null, OnWatchChanged)); 

Then listen to IsVisibleChanged :

 private static void OnWatchChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { if (obj == null) return; if (obj is Grid) { var grid = obj as Grid; var gs = e.NewValue as GridSplitter; if (gs != null) { gs.IsVisibleChanged += (_sender, _e) => { UpdateGrid( grid, (GridSplitter)_sender, (bool)_e.NewValue, (bool)_e.OldValue); }; } } } 

After viewing these changes, you need to save or restore the GridLength values ​​from the row or columns that you are viewing (for brevity, I only include rows):

 // Given: static Dictionary<DependencyObject, GridLength> oldValues; private static void UpdateGrid(Grid grid, GridSplitter gridSplitter, bool newValue, bool oldValue) { if (newValue) { // We're visible again switch (gridSplitter.ResizeDirection) { case GridResizeDirection.Columns: break; case GridResizeDirection.Rows: int ridx = (int)gridSplitter.GetValue(Grid.RowProperty); var prev = grid.RowDefinitions.ElementAt(GetPrevious(gridSplitter, ridx)); var curr = grid.RowDefinitions.ElementAt(GetNext(gridSplitter, ridx)); if (oldValues.ContainsKey(prev) && oldValues.ContainsKey(curr)) { prev.Height = oldValues[prev]; curr.Height = oldValues[curr]; } break; } } else { // We're being hidden switch (gridSplitter.ResizeDirection) { case GridResizeDirection.Columns: break; case GridResizeDirection.Rows: int ridx = (int)gridSplitter.GetValue(Grid.RowProperty); var prev = grid.RowDefinitions.ElementAt(GetPrevious(gridSplitter, ridx)); var curr = grid.RowDefinitions.ElementAt(GetNext(gridSplitter, ridx)); switch (gridSplitter.ResizeBehavior) { // Naively assumes only one type of collapsing! case GridResizeBehavior.PreviousAndCurrent: oldValues[prev] = prev.Height; prev.Height = new GridLength(1.0, GridUnitType.Star); oldValues[curr] = curr.Height; curr.Height = new GridLength(0.0); break; } break; } } } 

All that remains is a suitable implementation of GetPrevious and GetNext :

 private static int GetPrevious(GridSplitter gridSplitter, int index) { switch (gridSplitter.ResizeBehavior) { case GridResizeBehavior.PreviousAndNext: case GridResizeBehavior.PreviousAndCurrent: return index - 1; case GridResizeBehavior.CurrentAndNext: return index; case GridResizeBehavior.BasedOnAlignment: default: throw new NotSupportedException(); } } private static int GetNext(GridSplitter gridSplitter, int index) { switch (gridSplitter.ResizeBehavior) { case GridResizeBehavior.PreviousAndCurrent: return index; case GridResizeBehavior.PreviousAndNext: case GridResizeBehavior.CurrentAndNext: return index + 1; case GridResizeBehavior.BasedOnAlignment: default: throw new NotSupportedException(); } } 
+2
source

Suppose I have this XAML layout:

  <Grid Name="MyGrid"> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <MyControl1 ... Grid.Row="0" /> <GridSplitter Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Stretch" ShowsPreview="True" Height="5" /> <MyControl2 ... Grid.Row="2" /> </Grid> 

Then I can hide the second control (roll the splitter down) with this code (equivalent to setting Height="0" in XAML):

  MyGrid.RowDefinitions[2].Height = new GridLength(0); 

And cancel it with this code (equivalent to setting Height="1*" in XAML, which is the default for RowDefinition):

  MyGrid.RowDefinitions[2].Height = new GridLength(1, GridUnitType.Star); 

This is what the splitter makes hidden when the user moves it.

+4
source

This GridExpander controls that it inherits a GridSpliter form that can work for the job you need. The loan goes to Shemesh to write the original version of Silverlight, which I adapted for my use in WPF. I believe that I want this functionality almost everywhere I try to use GridSplitter, so it can be very convenient.

+3
source

Source: https://habr.com/ru/post/925702/


All Articles