wpflayoutpanelmarginclipping

Why do my panels clip all the way around the panel when made smaller than the explicit size?


Probably a confusing question title.

The Grid with the Red Rectangle is an example of how it should look.

The Grid with the Blue Rectangle (not appearing in the image) has a margin that forces the second grid to be smaller than I've explicitly set it. Which appears to cause WPF to flip out and hide everything outside of it's arranged bounds.

enter image description here

I've tried setting the Clip to be larger than the Grid.

The only way I've been able to avoid this is to write a custom panel that measures it's children with a constraint of PositiveInfinity, but then arranges the children with the correct width. That method has lots of problems. It's not good to lie to your children.

Anyway, here's the code:

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="NegativeMarginTooMuchClipping.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640"
Height="400">

<Grid>
    <StackPanel Width="600" Height="300">
    <Grid Margin="40,50,60,50" Background="#FFB8B8B8" Width="500" Height="50">
        <Rectangle Fill="Red" HorizontalAlignment="Left" Height="50" VerticalAlignment="Top" Width="50" Margin="0,-50,0,0"/>
    </Grid>
    <Grid Margin="40,50,61,50" Background="#FFB8B8B8" Width="500" Height="50">
        <Rectangle Fill="Blue" HorizontalAlignment="Left" Height="50" VerticalAlignment="Top" Width="50" Margin="0,-50,0,0"/>
    </Grid>
    </StackPanel>
</Grid>

Known issue? Am I doing it wrong? Need more clarification?


Solution

  • There are three things that go into to determining how something clips. The first two are ClipToBounds and Clip, but the third is a little more annoying and that is GetLayoutClip.

    By default, for UIElement the GetLayoutClip method will return either null or a RectangleGeometry the same size as the element, depending on the ClipToBounds property. FrameworkElement, and it's derivations, are much more complex though. Take a look in Reflector/ILSpy and you will see what I mean.

    You can override this behavior though. If you use something like the following as your Grid for the blue rectangle, then it will no longer be clipped:

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

    There is a great blog post on this here.