我有一个带有2列的网格,由GridSplitter使用以下XAML代码分隔:
<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
*我知道之前已经解决了,但它始终建议将列大小设置为*或在第一列设置maxWidth ...我不希望这样。
找到一个解决方案,但它的UGLY! :p ,任何人都有更清洁的方式来实现我想要的...... CODELESS(如果可能的话)?
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;
}
答案 0 :(得分:6)
基本问题是网格分割器的工作原理是调整左列的宽度,并假设右列星号以适应剩余空间。
这意味着您要解决的问题实际上是“我如何限制左列的最大宽度,以便右列不会太小?”。这基本上就是您的代码示例所做的事情。
如果您想要一个可以在XAML中实现的更便携的解决方案,请创建一个可应用于网格的Silverlight behavior(如下所示)。它将附加到父网格的SizeChanged
事件,并且几乎完全与您的代码片段相同,但是您可以将它们拖放到Blend中或将它们附加到XAML中。
以下是我为您举例的示例行为(基于您自己的代码):
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;
}
}
}
}
<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>
答案 1 :(得分:4)
在我看来,这是WPF GridSplitter中的一个错误。问题的根源是为Width列使用不同类型的值。
这不起作用:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" MinWidth="20" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" MinWidth="100" />
</Grid.ColumnDefinitions>
因为列[0]的宽度为“100”,所以显式数字类型,列[1]的宽度为“*”。但这会奏效:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="20" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" MinWidth="100" />
</Grid.ColumnDefinitions>
执行此操作时,GridSplitter会遵循左右“MinWidth”值。对我来说,这意味着WPF中的错误。
在我的情况下,我需要将左列设置为“Auto”,最小值为“Auto”,将“*”设置为最小值,但如果没有某种形式的话,似乎没有任何方法可以做到这一点。代码隐藏。我的猜测是,最简单的解决方案是只调整大小并使用自定义行为来替换列的“自动”功能(因为这是一列一次性修复),但我还没有做那。希望XAML看起来像这样:
<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” *“分别(或任何其他获得正确比率的数字)。
这不是微不足道的,但最终确实奏效了。我没有说明列跨越。
抱歉,我无法发布代码。