【问题标题】:Stop Gridsplitter stretching content beyond window停止 Gridsplitter 将内容拉伸到窗口之外
【发布时间】:2011-08-18 06:51:26
【问题描述】:

鉴于以下 XAML,我如何让 gridsplitter 尊重赋予第三行的 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>

【问题讨论】:

  • 您是否需要纯在 Xaml 中的解决方案,或者是否可以将代码添加到代码隐藏中?

标签: wpf gridsplitter


【解决方案1】:

按照您的代码的方式,这无法完成,伙计。这是因为 GridSplitter 的工作原理。

几点

  • GridSplitter 将始终在直接相邻的行/列上工作
  • 实际上,您的 MinHeight 受到尊重,但 GridSplitter 的增长请求也受到尊重,这导致 Grid 变得比您的窗口大
  • 当大小设置为自动时,行/列将始终根据其内容调整大小,不会变大也不会变小
  • 因此,如果 GridSplitter 夹在两个 * 大小的行/列之间,那么它会隐含地尊重您的 MinHeight,因为实际上它不会触及它

你有几个解决方案

  1. 在第 3 位置添加另一行 * 大小,并在第 3 行设置边框,RowSpan 为 2(因此第 3 行是真正调整大小的行,而第 4 行没有被触及。虽然这也会有副作用。
  2. 在 GridSplitter 上处理 DragEnter 和 PreviewMouseMove 事件的混合,跟踪焦点,并在达到特定大小时取消 (e.Handled = true) 事件。

这是我能想到的朋友,希望对我有所帮助。

【讨论】:

    【解决方案2】:

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

    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”。一切都像基本网格拆分器一样工作。

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

    【讨论】:

    • 在将其转换为 C# 并包含对基类的必要调用后,它按预期工作。正是我需要的。赞成。
    【解决方案3】:

    我找到了解决这个问题的另一种方法,但在一个更简单的情况下,我在一个窗口中只有两列我想调整大小。

    我想出的解决方案(在此处更详细地描述: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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-13
      • 2021-01-14
      • 1970-01-01
      • 2021-07-31
      相关资源
      最近更新 更多