Search code examples
wpf

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


I have a border element with rounded corners containing a 3x3 grid. The corners of the grid are sticking out of the border. How can I fix that? I tried using ClipToBounds but didn't get anywhere. Thanks for your help


Solution

  • 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;
        }