How to make the contents of a round-cornered border be also round-cornered?

Here are the highlights of this thread mentioned by Jobi

  • None of the decorators (i.e. Border) or layout panels (i.e. Stackpanel) come with this behavior out-of-the-box.
  • ClipToBounds is for layout. ClipToBounds does not prevent an element from drawing outside its bounds; it just prevents children's layouts from 'spilling'. Additionally ClipToBounds=True is not needed for most elements because their implementations dont allow their content's layout to spill anyway. The most notable exception is Canvas.
  • Finally Border considers the rounded corners to be drawings inside the bounds of its layout.

Here is an implementation of a class that inherits from Border and implements the proper functionality:

     /// <Remarks>
    ///     As a side effect ClippingBorder will surpress any databinding or animation of 
    ///         its childs UIElement.Clip property until the child is removed from ClippingBorder
    /// </Remarks>
    public class ClippingBorder : Border {
        protected override void OnRender(DrawingContext dc) {
            OnApplyChildClip();            
            base.OnRender(dc);
        }

        public override UIElement Child 
        {
            get
            {
                return base.Child;
            }
            set
            {
                if (this.Child != value)
                {
                    if(this.Child != null)
                    {
                        // Restore original clipping
                        this.Child.SetValue(UIElement.ClipProperty, _oldClip);
                    }

                    if(value != null)
                    {
                        _oldClip = value.ReadLocalValue(UIElement.ClipProperty);
                    }
                    else 
                    {
                        // If we dont set it to null we could leak a Geometry object
                        _oldClip = null;
                    }

                    base.Child = value;
                }
            }
        }

        protected virtual void OnApplyChildClip()
        {
            UIElement child = this.Child;
            if(child != null)
            {
                _clipRect.RadiusX = _clipRect.RadiusY = Math.Max(0.0, this.CornerRadius.TopLeft - (this.BorderThickness.Left * 0.5));
                _clipRect.Rect = new Rect(Child.RenderSize);
                child.Clip = _clipRect;
            }
        }

        private RectangleGeometry _clipRect = new RectangleGeometry();
        private object _oldClip;
    }

Pure XAML:

<Border CornerRadius="30" Background="Green">
    <Border.OpacityMask>
        <VisualBrush>
            <VisualBrush.Visual>
                <Border 
                    Background="Black"
                    SnapsToDevicePixels="True"
                    CornerRadius="{Binding CornerRadius, RelativeSource={RelativeSource AncestorType=Border}}"
                    Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Border}}"
                    Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Border}}"
                    />
            </VisualBrush.Visual>
        </VisualBrush>
    </Border.OpacityMask>
    <TextBlock Text="asdas das d asd a sd a sda" />
</Border>

Update: Found a better way to achieve the same result. You can also replace Border with any other element now.

<Grid>
    <Grid.OpacityMask>
        <VisualBrush Visual="{Binding ElementName=Border1}" />
    </Grid.OpacityMask>
    <Border x:Name="Border1" CornerRadius="30" Background="Green" />
    <TextBlock Text="asdas das d asd a sd a sda" />
</Grid>

Example