Элемент управления с отрицательным полем обрезается при изменении размера окна в WPF

Я пытаюсь понять, почему элемент границы обрезается при уменьшении ширины главного окна. Пожалуйста, посмотрите код блока ниже.

    <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>

Вот то, что граница появляется в оригинальной ширине окна:

Окно без изменения размера

введите описание изображения здесь

Как вы можете видеть, граница отображается за пределами контейнера из-за отрицательного верхнего поля, в данном случае -100. Это то, что я ожидаю от границы. Но когда я уменьшаю ширину основного окна, чтобы достичь правого края красного прямоугольника, внешняя часть границы обрезается.

Изменение размера окна

введите описание изображения здесь

Я попытался поместить этот элемент границы в пользовательский StackPanel, который переопределяет методы ArrangeOverride, MeasureOverride и GetLayoutClip, но, к сожалению, эти методы не вызываются при изменении размера главного окна.

Я ценю, если кто-то может объяснить мне, в чем причина и как обойти эту проблему. Большое спасибо.

2 ответа

Решение

Основываясь на объяснении @Marks, вот мое решение

  1. Создайте пользовательскую сетку и переопределите метод MeasureOverride.
  2. Замените внутреннюю сетку этой пользовательской сеткой

CustomGrid класс

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>

  1. Вы связываете синюю границу Width в главное окно Width, На будущее: если вы хотите привязать к ширине любого FrameworkElement привязать к его ActualWidth имущество.

  2. Порядок, в котором WPF рисует свои вещи, очень зависит от элемента управления, в котором они содержатся. Я бы сказал, в вашем случае внешний Grid рисует своих потомков, которые нуждаются в обновлении в порядке их определения. Так что вы можете идти до тех пор, пока внутренняя сетка меняется вместе с границей. Это так до тех пор, пока 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>
Другие вопросы по тегам