在 WPF 中调整 window 的大小时,负边距控件被截断

Negative-margin control get clipped when resizing the window in WPF

我试图理解为什么在减小主 window 的宽度时边框元素会被剪掉。 请看下面的代码块。

    <Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="300" Width="500" Name="MainWin">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>

        <Border Background="Blue" Grid.Row="0" BorderBrush="Black" Width="{Binding ElementName=MainWin, Path=Width}" />
        <Grid Grid.Row="1" Margin="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150" />
                <ColumnDefinition Width="150" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <StackPanel Grid.Column="0" Background="Black">
                <Border Background="White" Width="150" Height="150" BorderBrush="Black" BorderThickness="2"
                        Margin="0,-100,0,0">

                    <TextBlock Text="{Binding ElementName=MainWin, Path=Width}" FontSize="14" FontWeight="Bold"
                               HorizontalAlignment="Center"
                               VerticalAlignment="Center" />

                </Border>
            </StackPanel>
            <StackPanel Grid.Column="1" Background="Red" />
            <StackPanel Grid.Column="2" Background="Yellow" />
        </Grid>
    </Grid>
</Window>

原来window出现的边框宽度是这样的:

未调整大小window

如您所见,由于顶部边距为负,因此边框显示在其容器外部,在本例中为 -100。这就是我期望的边界。但是,当我减小主要 window 宽度以到达红色矩形的右边缘时,边框的外侧部分会被剪掉。

调整大小window

我试图将此边框元素放置在自定义 StackPanel 中,该 StackPanel 覆盖了 ArrangeOverride、MeasureOverride 和 GetLayoutClip 方法,但不幸的是,在调整主要 window 大小时这些方法未被调用。

如果有人能向我解释原因以及如何解决此问题,我将不胜感激。 非常感谢。

  1. 您正在将蓝色边框的 Width 绑定到 MainWindow 的 Width。 对于未来:如果你想绑定到任何 FrameworkElement 的宽度,绑定到它的 ActualWidth 属性.

  2. WPF 绘制内容的顺序完全取决于包含的控件。我会说在你的情况下,外部 Grid 绘制它的 children 需要按照它们定义的顺序更新 。因此,只要内部网格随边框一起变化,您就可以开始了。只要第三列的Width发生变化就是这样。一旦它为 0,就没有更多变化,因此它不会更新。

  3. (2)是推测=)

  4. 不要做(1),没必要

  5. 使用一个网格

一些XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>        
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition Width="150" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
    <Border Background="Blue" BorderBrush="Black" Grid.ColumnSpan="3"/>
    <StackPanel Grid.Column="0" Grid.Row="1" Background="Black" >
      <Border Background="White" Width="150" Height="150" BorderBrush="Black" BorderThickness="2"  Margin="0,-100,0,0">
        <TextBlock Text="{Binding ElementName=MainWin, Path=ActualWidth}" FontSize="14" FontWeight="Bold"
                           HorizontalAlignment="Center"
                           VerticalAlignment="Center" />
      </Border>
    </StackPanel>
    <StackPanel Grid.Column="1" Grid.Row="1" Background="Red" />
    <StackPanel Grid.Column="2" Grid.Row="1" Background="Yellow" />          
</Grid>

根据@Marks的解释,这是我的解决方案

  1. 创建自定义网格并覆盖 MeasureOverride 方法
  2. 用这个自定义网格替换内部网格

自定义网格class

public class CustomGrid : Grid
{
    private double _originalHeight = 0;

    protected override Size MeasureOverride(Size constraint)
    {
        Size? size = null;
        if (constraint.Width <= 300)
        {
            size = new Size(constraint.Width, _originalHeight);
        }
        else
        {
            size = base.MeasureOverride(constraint);
            _originalHeight = constraint.Height;

        }
        return size.Value;
    }

}

XAML代码

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wpfApplication1="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="300" Width="500" Name="MainWin">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>

    <Border Background="Blue" Grid.Row="0" BorderBrush="Black" Width="{Binding ElementName=MainWin, Path=Width}" />
    <wpfApplication1:CustomGrid Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition Width="150" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="0" Background="Black">
            <Border Background="White" Width="150" Height="150" BorderBrush="Black" BorderThickness="2"
                    Margin="0,-100,0,0">

                <TextBlock Text="{Binding ElementName=MainWin, Path=Width}" FontSize="14" FontWeight="Bold"
                           HorizontalAlignment="Center"
                           VerticalAlignment="Bottom" />

            </Border>
        </StackPanel>
        <StackPanel Grid.Column="1" Background="Red" />
        <StackPanel Grid.Column="2" Background="Yellow" />
    </wpfApplication1:CustomGrid>
</Grid>