wpfresizemarginnegative-numberclipped

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


I try to understand why a border element get clipped when reducing the width of the main window. Please take a look the code block below.

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

Here is what the border appears in the original window width:

Non-resized window

enter image description here

As you can see that the border is displayed outside its container because of the negative top margin, -100 in this case. This is what I expect to have for the border. But when I reduce the main window width to reach the right edge of the red rectangle the outside part of the border get clipped.

Resized window

enter image description here

I have tried to place this border element inside a custom StackPanel which overrides ArrangeOverride, MeasureOverride and GetLayoutClip method but unfortunately these methods are not invoked when the main window is being resized.

I appreciate if somebody can explain me what the reason is and how to work around with this issue. Thanks a lot.


Solution

  • Based on the explanation of @Marks, here is my solution

    1. Create a custom grid and overrides MeasureOverride method
    2. Replace the inner grid by this custom grid

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

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