2

我正在设计一个需要方形的用户控件,并尽可能多地填充给定的空间(为了给出一些上下文,它是一个检查板)。

我的用户控件如下所示:

<Grid>
    <!-- My 8 lines / colums, etc. , sized with "1*" to have equal lines -->
</Grid>

现在我只想说“这个网格必须是方形的,无论它必须扩展什么空间”。

徒劳的尝试解决方案:

  1. 我不能使用 aUniformGrid因为我实际上还有行和列的名称,所以我有一个不同大小的前导标题行和列。

  2. 如果我使用 a ViewboxUniform它就会一团糟。

  3. 我尝试使用经典

    <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;
}
4

5 回答 5

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 测试了这两种方法,并且在扩展/收缩时保持正方形大小。请注意,症结中的两种方法都使用相同的逻辑(只是一个快速模型),如果您将逻辑更新为仅在宽度更改时更新高度,反之亦然,而不是两者并取消,您可能会获得更好的性能如果不需要,一起调整大小

于 2013-03-24T22:09:10.857 回答
1

尝试将您的网格放入 ViewBox:http: //msdn.microsoft.com/en-us/library/system.windows.controls.viewbox.aspx

这是我想出的代码示例:

用户控件:

<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 属性。

于 2013-03-25T08:39:27.930 回答
0

您可以将Height属性绑定到ActualWidth而不是Width

<Grid Height="{Binding ActualWidth, RelativeSource={RelativeSource Self}}">
    ...
</Grid>

但是,更好的解决方案是使用 Viewbox。避免它“搞砸”的诀窍是通过为 Width 和 Height 定义(合理的)相等值来使其 Child 为正方形:

<Viewbox>
    <Grid Width="500" Height="500">
        ...              
    </Grid>
</Viewbox>
于 2013-03-24T21:55:19.890 回答
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;
}
于 2018-08-08T19:10:20.853 回答
0

我已经通过从父控件的大小更改事件中设置包含控件的边距来解决这个问题。在我的例子中,我有一个名为 SudokuBoard 的“数独网格”用户控件,位于一个名为 MainGrid 的标准网格控件(填充主窗口)中,它只需要以下代码;

    private void MainGrid_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        double verticalMargin = Math.Max((e.NewSize.Height - e.NewSize.Width)*0.5, 0.0);
        double horizontalMargin = Math.Max((e.NewSize.Width - e.NewSize.Height)*0.5, 0.0);
        SudokuBoard.Margin = new Thickness(horizontalMargin, verticalMargin, horizontalMargin, verticalMargin); 
    }
于 2021-12-29T09:35:57.120 回答