我正在设计一个需要为方形的用户控件,并填充给出的空间(给出一些上下文,它是一个检查板)。
我的用户控件如下:
<Grid>
<!-- My 8 lines / colums, etc. , sized with "1*" to have equal lines -->
</Grid>
现在我只想说“无论它有什么扩展空间,这个网格都必须是正方形”。
徒劳地尝试解决方案:
我不能使用UniformGrid
,因为我实际上有这些行的名称。另外,我有一个不同大小的前导标题行和列。
如果我将Viewbox
与Uniform
一起使用,那么一切都会混乱。
我尝试使用经典
<Grid Height="{Binding RelativeSource={RelativeSource Self}, Path=Width}"> ... </Grid>
但只有在我手动设置Width
属性时才有效。否则,将忽略此约束。
结论
我不在乎,我真的想避免手动设置Width
/ Height
,因为此控件可用于多个不同的地方(ListItem
模板,游戏,等...)。
来自建议的解决方案:
可以使用一些代码隐藏的解决方案。我没有找到只有XAML的解决方案。
网格现在是:
<Grid SizeChanged="Board_FullControlSizeChanged">...</Grid>
事件处理程序是:
private void Board_FullControlSizeChanged(object sender, SizeChangedEventArgs args)
{
double size = Math.min (args.NewSize.Height, args.NewSize.Width);
((Grid)sender).Width = size;
((Grid)sender).Height = size;
}
答案 0 :(得分:3)
我最初尝试修改您对ActualWidth
的绑定,但当Grid
是顶级元素时,它仍然不起作用,并且在某些情况下,它最终扩展控件的范围超出可用大小。因此尝试了其他一些获得所需输出的方法。
有两种方法可能解决这个问题:
因为这是一个视图相关的问题(不破坏MVVM,保持正方形,如果你有一点代码隐藏,你可以做类似的事情)
private void OnSizeChanged(object sender, SizeChangedEventArgs e) {
double minNewSizeOfParentUserControl = Math.Min(e.NewSize.Height, e.NewSize.Width);
mainGrid.Width = minNewSizeOfParentUserControl;
mainGrid.Height = minNewSizeOfParentUserControl;
}
在您的xaml中,您可以将主要顶级网格命名为“mainGrid”,并将UserControl
尺寸更改事件处理程序附加到上述函数而不是Grid
本身。
但是,如果你因任何原因完全讨厌代码隐藏,你可能会更加花哨并创建一种行为,例如
public class GridSquareSizeBehavior : Behavior<Grid> {
private UserControl _parent;
protected override void OnAttached() {
DependencyObject ucParent = AssociatedObject.Parent;
while (!(ucParent is UserControl)) {
ucParent = LogicalTreeHelper.GetParent(ucParent);
}
_parent = ucParent as UserControl;
_parent.SizeChanged += SizeChangedHandler;
base.OnAttached();
}
protected override void OnDetaching() {
_parent.SizeChanged -= SizeChangedHandler;
base.OnDetaching();
}
private void SizeChangedHandler(object sender, SizeChangedEventArgs e) {
double minNewSizeOfParentUserControl = Math.Min(e.NewSize.Height, e.NewSize.Width);
AssociatedObject.Width = minNewSizeOfParentUserControl;
AssociatedObject.Height = minNewSizeOfParentUserControl;
}
}
对于xaml的行为如下:
<Grid>
<i:Interaction.Behaviors>
<local:GridSquareSizeBehavior />
</i:Interaction.Behaviors>
</Grid>
用Snoop测试这两种方法,并在扩展/收缩时保持方形尺寸。请注意,关键字中的两种方法都使用相同的逻辑(只是一个快速的模型),如果更新逻辑只更新宽度更改宽度,反之亦然,并且取消两者,您可能会挤出一些更好的性能如果不需要,一起调整大小
答案 1 :(得分:1)
尝试将网格放入ViewBox:http://msdn.microsoft.com/en-us/library/system.windows.controls.viewbox.aspx
这是我提出的代码示例:
usercontrol:
<UserControl x:Class="StackOverflow.CheckBoard"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Viewbox>
<Grid Background="Red" Height="200" Width="200">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Content="testing" Grid.Row="0"/>
<Button Content="testing" Grid.Row="1"/>
<Button Content="testing" Grid.Row="2"/>
</Grid>
</Viewbox>
</UserControl>
主窗口:
<Window x:Class="StackOverflow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StackOverflow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:AllNoneCheckboxConverter x:Key="converter"/>
</Window.Resources>
<Grid>
<StackPanel>
<local:CheckBoard MaxWidth="80"/>
</StackPanel>
</Grid>
</Window>
此Viewbox将执行的操作是将控件缩放到给定的空间。由于视图框内的网格是方形的,因此网格始终保持正方形。尝试使用我在MainWindow中使用的MaxWidth属性。
答案 2 :(得分:0)
您可以将Height
属性绑定到ActualWidth
而不是Width
:
<Grid Height="{Binding ActualWidth, RelativeSource={RelativeSource Self}}">
...
</Grid>
但是,更好的解决方案是使用Viewbox。避免它“混乱”的诀窍是通过为宽度和高度定义(合理的)相等值来使其子方格:
<Viewbox>
<Grid Width="500" Height="500">
...
</Grid>
</Viewbox>
答案 3 :(得分:0)
在适合您的位置注册(通常在构造函数或OnAttached()中):
SizeChanged += Square;
并使用此值处理大小:
private void Square(object sender, SizeChangedEventArgs e)
{
if (e.HeightChanged) Width = e.NewSize.Height;
else if (e.WidthChanged) Height = e.NewSize.Width;
}