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

发布于 2024-11-05 06:35:31 字数 1790 浏览 6 评论 0原文

鉴于下面的 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>

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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

扎心 2024-11-12 06:35:31

按照你的代码的方式,这是不可能完成的,伙计。这是由 GridSplitter 的工作原理决定的。

几点

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

你有一些解决方案

  1. 在第三个位置添加另一行,其大小为*,并将边框放在第3行,RowSpan为2(所以第三行是确实调整了大小,并且您的第四行没有被触及,尽管这也会产生副作用,
  2. 在 GridSplitter 上处理 DragEnter 和 PreviewMouseMove 事件,跟踪焦点并取消。 (e.Handled = true) 当达到一定大小时发生的事件,

这就是我能想到的,希望我能有所帮助。

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.

晒暮凉 2024-11-12 06:35:31

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

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

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

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

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.

檐上三寸雪 2024-11-12 06:35:31

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

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

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文