Элемент управления с отрицательным полем обрезается при изменении размера окна в 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, вот мое решение
- Создайте пользовательскую сетку и переопределите метод MeasureOverride.
- Замените внутреннюю сетку этой пользовательской сеткой
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>
Вы связываете синюю границу
Width
в главное окноWidth
, На будущее: если вы хотите привязать к ширине любогоFrameworkElement
привязать к егоActualWidth
имущество.Порядок, в котором WPF рисует свои вещи, очень зависит от элемента управления, в котором они содержатся. Я бы сказал, в вашем случае внешний
Grid
рисует своих потомков, которые нуждаются в обновлении в порядке их определения. Так что вы можете идти до тех пор, пока внутренняя сетка меняется вместе с границей. Это так до тех пор, покаWidth
третьего столбца изменений. Как только он в 0, больше нет изменений, поэтому он не обновляется.(2) это спекуляция =)
не делай (1), в этом нет необходимости
Используйте одну сетку
Немного 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>