GridSplitter MinWidth with fixed size
我有一个由 GridSplitter 分隔的 2 列的网格,使用以下 XAML 代码:
1 2 3 4 5 6 7 8 9 10 11 | <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="100" MinWidth="20" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="*" MinWidth="100" /> </Grid.ColumnDefinitions> <Rectangle Fill="Blue" /> <GridSplitter Grid.Column="1" Background="LightGray" HorizontalAlignment="Stretch" /> <Rectangle Fill="Yellow" Grid.Column="2" /> </Grid> |
问题:右侧列的MinWidth被忽略
- 当页面加载时,我绝对需要第一列宽度为"100px",所以它不能是*大小。
- 我不想在第一列上设置 MaxWidth
*我知道之前已经解决过,但它总是建议将列大小设置为 * 或在第一列上设置 maxWidth...我不想要那个。
找到了解决方案,但它太丑了! :p,任何人都有更简洁的方法来实现我想要的……无码(如果可能的话)?
1 2 3 4 5 6 7 | private void Grid_SizeChanged(object sender, SizeChangedEventArgs e) { var g = (Grid)sender; Double maxW = e.NewSize.Width - g.ColumnDefinitions[2].MinWidth - g.ColumnDefinitions[1].ActualWidth; g.ColumnDefinitions[0].MaxWidth = maxW; } |
基本问题是网格拆分器仅通过调整左列的宽度来工作,并假定右列将按星形大小调整以适应剩余空间。
这意味着您要解决的问题实际上是"如何限制左列的最大宽度,以使右列不会变得太小?"。这基本上就是您的代码示例正在做的事情。
如果您想要一个更便携的解决方案,可以在 XAML 中实现,请创建一个可以应用于网格的 Silverlight 行为(如下所示)。它将附加到父网格的
以下是我为您整理的示例行为(基于您自己的代码):
MinWidthSplitterBehavior.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | using System; using System.Windows; using System.Windows.Controls; using System.Windows.Interactivity; namespace GridSplitterMinWidth { public class MinWidthSplitterBehavior : Behavior<Grid> { public Grid ParentGrid { get; set; } protected override void OnAttached() { base.OnAttached(); ParentGrid = this.AssociatedObject as Grid; ParentGrid.SizeChanged += parent_SizeChanged; } void parent_SizeChanged(object sender, SizeChangedEventArgs e) { if (ParentGrid.ColumnDefinitions.Count == 3) { Double maxW = e.NewSize.Width - ParentGrid.ColumnDefinitions[2].MinWidth - ParentGrid.ColumnDefinitions[1].ActualWidth; ParentGrid.ColumnDefinitions[0].MaxWidth = maxW; } } protected override void OnDetaching() { base.OnDetaching(); if (ParentGrid != null) { ParentGrid.SizeChanged -= parent_SizeChanged; } } } } |
并像这样使用它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <UserControl x:Class="GridSplitterMinWidthApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:GridSplitterMinWidth="clr-namespace:GridSplitterMinWidth" xmlns:interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:Controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="100" MinWidth="20" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="*" MinWidth="100" /> </Grid.ColumnDefinitions> <interactivity:Interaction.Behaviors> <GridSplitterMinWidth:MinWidthSplitterBehavior/> </interactivity:Interaction.Behaviors> <Rectangle Fill="Blue" /> <Controls:GridSplitter Grid.Column="1" Background="LightGray" HorizontalAlignment="Stretch"> </Controls:GridSplitter> <Rectangle Fill="Yellow" Grid.Column="2" /> </Grid> </Grid> </UserControl> |
在我看来,这似乎是 WPF GridSplitter 中的一个错误。问题的根源在于对 Width 列使用不同类型的值。
这行不通:
1 2 3 4 5 | <Grid.ColumnDefinitions> <ColumnDefinition Width="100" MinWidth="20" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="*" MinWidth="100" /> </Grid.ColumnDefinitions> |
因为列 [0] 的宽度为 "100",是显式数字类型,而列 [1] 的宽度为 "*"。但这会起作用:
1 2 3 4 5 | <Grid.ColumnDefinitions> <ColumnDefinition Width="*" MinWidth="20" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="*" MinWidth="100" /> </Grid.ColumnDefinitions> |
执行此操作时,GridSplitter 会遵守左右 "MinWidth" 值。对我来说,这意味着 WPF 中的错误。
在我的情况下,我需要将左列设置为 "Auto" 最小值,将右列设置为 "*" 最小值,但似乎没有任何办法没有某种形式的代码隐藏。我的猜测是,最简单的解决方案是 * 调整所有内容的大小并使用自定义行为来替换列的"自动"功能(因为这是一列一次性修复),但我还没有要做到这一点。希望 XAML 看起来像这样:
1 2 3 4 5 6 7 8 9 10 11 | <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" MinWidth="20" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="*" MinWidth="100" /> </Grid.ColumnDefinitions> <interactivity:Interaction.Behaviors> <MyBehaviors:GridColumnStarSizedToAutoBehavior Column="0"/> </interactivity:Interaction.Behaviors> ... </Grid> |
更新*:我实现了上面这篇文章中提到的行为。由于网格限制,它并不像我希望的那么简单。由于公司限制,我无法发布解决方案,但我可以提供一些提示。我遇到的最大问题是,即使有行为代码隐藏,您也无法真正摆脱星号大小,因为它使 MinWidth 停止为星号大小的列工作。
为了弥补这一点,需要处理网格的所有列。您必须采用您想要自动调整大小的列,通过按列获取 UIElements 并对其使用 Measure 来确定其子项的所需大小,然后将它们的星号值更改为总可用星号间距的百分比.您还必须相应地调整非自动星号大小的列星号值。
作为一个例子,考虑一个有 3 列的网格:第一个星形大小的 MinWidth 我们希望是自动的,第二个自动大小的没有 MinWidth,第三个星形大小的有 MinWidth。如果控件是 100 单位宽,并且第一列的内容需要 25 个像素,第三列的内容需要 5 个像素,则代码必须将第一列和最后一列的星号设置为 "25*" 并且"70*" 分别(或任何其他获得正确比率的数字)。
这不是微不足道的,但最终确实奏效了。我没有考虑列跨越。
抱歉,我无法发布代码。