username username - 25 days ago 8
C# Question

Border with negative margin disappears when resizing window

I have a grid and two border elements inside the grid. When I make my window smaller, the outer border disappears. Does anybody know why and how do I prevent it from disappearing?
Here is the layout of the main window:

<Window x:Class="TestBorder.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestBorder"
mc:Ignorable="d"
Title="MainWindow" Height="170" Width="225">
<Grid Margin="5" Height="100" VerticalAlignment="Top">
<Border BorderBrush="LightBlue" BorderThickness="5" Margin="-5"/>
<Border BorderBrush="Orange" BorderThickness="5"/>
</Grid>
</Window>


Here is what happens when I resize it:

enter image description here

The outer (blue) border is not visible if I make the window smaller. I know it is possible to workaround it, but I'd like to know why this is happening.

Answer

This happens because the Grid element clips the content when it cannot display it in full size. Even though the UIElement base class doesn't do any clipping unless ClipToBounds is set, the intermediate FrameworkElement class overrides this behavior and clips the content when it doesn't fit the area. The Geometry for a clipping mask is determined by GetLayoutClip() method. Margins are subtracted from the clipped area and as a result the outer border disappears.

From MSDN on FrameworkElement.GetLayoutClip():

Returns a geometry for a clipping mask. The mask applies if the layout system attempts to arrange an element that is larger than the available display space.

Remarks: Margins will be subtracted from the layoutSlotSize as part of layout system behavior.

A returned null reference indicates that no clipping will occur. The default implementation always returns null when ClipToBounds is false. This method overrides UIElement.GetLayoutClip. The FrameworkElement implementation uses MaxHeight and MaxWidth in its calculations. Several subclasses of FrameworkElement override this method again.

It is possible to use a grid that will not do any clipping at all (taken from this answer):

public class MyGrid : Grid 
{
    protected override Geometry GetLayoutClip(Size layoutSlotSize) 
    {
        return null;
    }
}