WPF 不需要的网格分割器行为

发布于 2024-08-28 18:55:21 字数 1051 浏览 8 评论 0原文

我有一个包含 3 列的简单网格(其中一列包含网格分割器)。当调整网格大小并且左列达到其最小宽度时,它不会不执行任何操作,而是会增加右列的宽度。谁能帮我阻止这一切吗?

我无法设置右列的最大宽度,因为网格本身也会调整大小。

这是一些显示问题的示例代码。调整大小时,将鼠标移到红色区域上:

XAML:

<Grid DockPanel.Dock="Top" Height="200">
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="200" Width="*" />
        <ColumnDefinition Width="3" />
        <ColumnDefinition MinWidth="120" Width="240" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Rectangle Fill="Red" Grid.Row="0" Grid.Column="0" />
    <DockPanel LastChildFill="True" Grid.Row="0" Grid.Column="2" >
        <Rectangle DockPanel.Dock="Right" Width="20" Fill="Blue" />
        <Rectangle Fill="Green" />
    </DockPanel>
    <GridSplitter Background="LightGray" Grid.Row="0" Grid.Column="1" Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>

I have a simple grid with 3 columns (one of which contains a grid splitter). When resizing the grid and the left column reaches its minimum width, instead of doing nothing it increases the width of the right column. Could anyone help me stop this?

I can't set the max width of the right column, because the grid itself also resizes.

Here's some sample code that shows the problem. While resizing, move the mouse over the red area:

XAML:

<Grid DockPanel.Dock="Top" Height="200">
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="200" Width="*" />
        <ColumnDefinition Width="3" />
        <ColumnDefinition MinWidth="120" Width="240" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Rectangle Fill="Red" Grid.Row="0" Grid.Column="0" />
    <DockPanel LastChildFill="True" Grid.Row="0" Grid.Column="2" >
        <Rectangle DockPanel.Dock="Right" Width="20" Fill="Blue" />
        <Rectangle Fill="Green" />
    </DockPanel>
    <GridSplitter Background="LightGray" Grid.Row="0" Grid.Column="1" Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>

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

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

发布评论

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

评论(3

我不是你的备胎 2024-09-04 18:55:21

我知道这有点晚了,但我刚刚遇到了这个问题,这是我的解决方案。不幸的是它不够通用,它只适用于具有两列的网格,但它可能可以进一步适应。然而,它解决了所描述的问题和我自己的问题,所以这里是:

解决方案包括黑客或解决方法,无论你想如何称呼它。您不必为左列和右列声明 MinWidth,而是为第一列声明 MinWidth 和 MaxWidth。这意味着 GridSplitter 不会移动到定义位置的右侧。到目前为止,一切都很好。

下一个问题是,如果我们有一个可调整大小的容器(在我的例子中是窗口),这还不够。这意味着我们无法将左列放大到我们想要的程度,即使第二列可能有足够的空间。幸运的是,有一个解决方案:绑定 Grid ActualWidth 并使用加法转换器。转换器参数实际上是右列所需的 MinWidth,显然是负值,因为我们需要从网格宽度中减去它。您也可以使用 SubtractConvertor,但这取决于您。

这是 xaml 和代码:

<Grid Background="{DynamicResource MainBackground}" x:Name="MainGrid" >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" MinWidth="100" MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType=Grid}, Converter={Converters:AdditionConverter}, ConverterParameter=-250}" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <GridSplitter  Width="3" VerticalAlignment="Stretch" Grid.Column="0"/>
    <!-- your content goes here -->
</Grid>

以及转换器:

[ValueConversion(typeof(double), typeof(double))]
public class AdditionConverter : MarkupExtension, IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        double dParameter;
        if (targetType != typeof(double) ||
            !double.TryParse((string)parameter, NumberStyles.Any, CultureInfo.InvariantCulture, out dParameter))
        {
            throw new InvalidOperationException("Value and parameter passed must be of type double");
        }
        var dValue = (double)value;
        return dValue + dParameter;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    #endregion

    #region Overrides of MarkupExtension

    /// <summary>
    /// When implemented in a derived class, returns an object that is set as the value of the target property for this markup extension. 
    /// </summary>
    /// <returns>
    /// The object value to set on the property where the extension is applied. 
    /// </returns>
    /// <param name="serviceProvider">Object that can provide services for the markup extension.
    ///                 </param>
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    #endregion
}

我希望这有帮助,

Mihai Drebot

I know this is a bit late, but I just run into this problem, and here is my solution. Unfortunately it is not general enough, it only works for a grid with two columns, but it can probably be adapted farther. However, it solves the described problem and my own, so here goes:

The solution consists in a hack or workaround, however you want to call it. Instead of declaring MinWidth for both the left and right column, you declare a MinWidth and a MaxWidth for the first column. This means that the GridSplitter won't move right of a defined location. So far, so good.

The next problem is that if we have a resizable container (the window in my case), this is not enough. It means that we cannot enlarge the left column as much as we want, even though there might be plenty of space for the second one. Fortunately, there is a solution: binding on the Grid ActualWidth and using an addition converter. The converter parameter will actually be the desired MinWidth for the right column, obviously the negative value, since we need to subtract it from the Grid Width. You could also use a SubtractConvertor, but that is up to you.

Here goes the xaml and code:

<Grid Background="{DynamicResource MainBackground}" x:Name="MainGrid" >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" MinWidth="100" MaxWidth="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType=Grid}, Converter={Converters:AdditionConverter}, ConverterParameter=-250}" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <GridSplitter  Width="3" VerticalAlignment="Stretch" Grid.Column="0"/>
    <!-- your content goes here -->
</Grid>

and the converter:

[ValueConversion(typeof(double), typeof(double))]
public class AdditionConverter : MarkupExtension, IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        double dParameter;
        if (targetType != typeof(double) ||
            !double.TryParse((string)parameter, NumberStyles.Any, CultureInfo.InvariantCulture, out dParameter))
        {
            throw new InvalidOperationException("Value and parameter passed must be of type double");
        }
        var dValue = (double)value;
        return dValue + dParameter;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    #endregion

    #region Overrides of MarkupExtension

    /// <summary>
    /// When implemented in a derived class, returns an object that is set as the value of the target property for this markup extension. 
    /// </summary>
    /// <returns>
    /// The object value to set on the property where the extension is applied. 
    /// </returns>
    /// <param name="serviceProvider">Object that can provide services for the markup extension.
    ///                 </param>
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    #endregion
}

I hope this helps,

Mihai Drebot

我为君王 2024-09-04 18:55:21

这种方法是一种 hack,但可以达到预期的效果。尝试在 Window.SizeChanged 事件上放置一个事件处理程序以设置第一个 columndef 的 maxWidth。例如:

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
     int borderBuffer = 9;
     //              AppWindow Size    Splitter Width     Far Column Min  FudgeFactor                
     Col0.MaxWidth = e.NewSize.Width - Col1.Width.Value - Col2.MinWidth - borderBuffer;
}

我需要使用此方法来防止网格顶行中的第三方控件由于 gridSplitter 忽略宽度设置为“自动”的列的最小/最大宽度而产生一些不需要的换行。 borderBuffer 可能需要根据您的情况进行调整。在我的例子中,基于几何/列/边框宽度, borderBuffer 并没有完全有意义 - 它只是适用于我的布局的神奇数字。

如果有人能提出更清洁的解决方案,我很乐意使用它。这个解决方案让我想起了痛苦地尝试强制 VB6 调整控件大小 - 恶心。但就目前而言,它比网格顶行上的项目由于意外的包装而被隐藏要好。

This approach is a hack but can be used for the desired effect. Try putting an event handler on the Window.SizeChanged event to set the maxWidth of the first columndef. For example:

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
     int borderBuffer = 9;
     //              AppWindow Size    Splitter Width     Far Column Min  FudgeFactor                
     Col0.MaxWidth = e.NewSize.Width - Col1.Width.Value - Col2.MinWidth - borderBuffer;
}

I needed to use this method to prevent a third party control in the top row of the grid from having some undesirable wrapping resulting from when the gridSplitter disregards the min/max width of the column with width set to "Auto". The borderBuffer may need to be adjusted for your case. The borderBuffer in my case didn't make perfect sense based on the geometry/column/border widths - it was just the magic number that worked for my layout.

If someone can come up with a cleaner solution, I'd love to use it instead. This solution reminds me of painfully trying to force VB6 to resize controls - yuck. But for now, it beats having items on the top row of my grid from getting hidden due to unexpected wrapping.

享受孤独 2024-09-04 18:55:21

我通过将列定义中的 * 更改为 Auto 并将 240 更改为 * 来阻止这种不良行为。

I got this undesirable behaviour to stop by changing the * in the columndefinition to Auto and the 240 to *.

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