停止Gridsplitter将内容拉伸到窗口之外

时间:2011-05-04 06:46:26

标签: wpf gridsplitter

鉴于以下XAML,我如何让gridsplitter尊重给第3行的MinHeight并将内容保留在我的窗口内?

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

3 个答案:

答案 0 :(得分:23)

你的代码的方式,这不能成为伙伴。这是由于GridSplitter的工作原理。

几点

  • GridSplitter将始终处理直接相邻的行/列
  • 实际上,你的MinHeight是受到尊重的,但是GridSplitter的要求也越来越受到尊重,这导致网格的增长大于你的窗口
  • 当尺寸设置为自动时,行/列将始终根据其内容调整大小,而不是更大,而不是更小
  • 因此,如果GridSplitter夹在两个*大小的行/列之间,那么它会隐含地尊重你的MinHeight,因为实际上它不会触及它

你有几个解决方案

  1. 在第3个位置添加另一行* size,并在第3行使用RowSpan为2的边框(因此第3行是真正调整大小的行,并且未触及第4行。虽然这样也有副作用。
  2. 在GridSplitter上处理DragEnter和PreviewMouseMove事件的混合,跟踪焦点,并在达到特定大小时取消(e.Handled = true)事件。
  3. 这是我能想到的伙伴,希望我能得到一些帮助。

答案 1 :(得分:1)

我创建了一个自定义网格分割器类,它不允许网格分割器离开窗口的边缘(底部或侧面)。

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

结束班

在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"/>

要设置的自定义属性是“SplitterDirection”和“MinimumDistanceFromEdge”。一切都像基本网格分割器一样工作。

这使用鼠标事件来确定用户拖动拆分器的窗口中的位置,并在事件太靠近边缘时处理事件。

答案 2 :(得分:-1)

我找到了另一个解决这个问题的方法,虽然在一个更简单的例子中,我只是在一个窗口中有两列,我想调整大小。

我提出的解决方案(在此更详细地描述:https://stackoverflow.com/a/46924893/6481970)是为网格调整大小,GridSplitter移动时以及窗口大小调整时添加事件回调(以处理您调整窗口大小以不再适合内容的情况,因为网格不会自动调整大小以适应较小的窗口。)

以下是一些简化的代码:

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#代码背后:

C0.MaxWidth = Math.Min(ResizeGrid.ActualWidth, ActualWidth) - (C2.MinWidth + 5);