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
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
Here are the highlights of this thread mentioned by Jobi
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;
}
Make the grid smaller or the border larger. So that the border element completely contains the grid.
Alternatively see if you can make the grid's background transparent, so that the "sticking out" isn't noticeable.
Update: Oops, didn't notice this was a WPF question. I'm not familiar with that. This was general HTML/CSS advice. Maybe it helps...
I don't like to use a custom control. Created a behavior instead.
using System.Linq;
using System.Windows;
using System.Windows.Interactivity;
/// <summary>
/// Base class for behaviors that could be used in style.
/// </summary>
/// <typeparam name="TComponent">Component type.</typeparam>
/// <typeparam name="TBehavior">Behavior type.</typeparam>
public class AttachableForStyleBehavior<TComponent, TBehavior> : Behavior<TComponent>
where TComponent : System.Windows.DependencyObject
where TBehavior : AttachableForStyleBehavior<TComponent, TBehavior>, new()
{
#pragma warning disable SA1401 // Field must be private.
/// <summary>
/// IsEnabledForStyle attached property.
/// </summary>
public static DependencyProperty IsEnabledForStyleProperty =
DependencyProperty.RegisterAttached("IsEnabledForStyle", typeof(bool),
typeof(AttachableForStyleBehavior<TComponent, TBehavior>), new FrameworkPropertyMetadata(false, OnIsEnabledForStyleChanged));
#pragma warning restore SA1401
/// <summary>
/// Sets IsEnabledForStyle value for element.
/// </summary>
public static void SetIsEnabledForStyle(UIElement element, bool value)
{
element.SetValue(IsEnabledForStyleProperty, value);
}
/// <summary>
/// Gets IsEnabledForStyle value for element.
/// </summary>
public static bool GetIsEnabledForStyle(UIElement element)
{
return (bool)element.GetValue(IsEnabledForStyleProperty);
}
private static void OnIsEnabledForStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement uie = d as UIElement;
if (uie != null)
{
var behColl = Interaction.GetBehaviors(uie);
var existingBehavior = behColl.FirstOrDefault(b => b.GetType() ==
typeof(TBehavior)) as TBehavior;
if ((bool)e.NewValue == false && existingBehavior != null)
{
behColl.Remove(existingBehavior);
}
else if ((bool)e.NewValue == true && existingBehavior == null)
{
behColl.Add(new TBehavior());
}
}
}
}
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
/// <summary>
/// Behavior that creates opacity mask brush.
/// </summary>
internal class OpacityMaskBehavior : AttachableForStyleBehavior<Border, OpacityMaskBehavior>
{
protected override void OnAttached()
{
base.OnAttached();
var border = new Border()
{
Background = Brushes.Black,
SnapsToDevicePixels = true,
};
border.SetBinding(Border.CornerRadiusProperty, new Binding()
{
Mode = BindingMode.OneWay,
Path = new PropertyPath("CornerRadius"),
Source = AssociatedObject
});
border.SetBinding(FrameworkElement.HeightProperty, new Binding()
{
Mode = BindingMode.OneWay,
Path = new PropertyPath("ActualHeight"),
Source = AssociatedObject
});
border.SetBinding(FrameworkElement.WidthProperty, new Binding()
{
Mode = BindingMode.OneWay,
Path = new PropertyPath("ActualWidth"),
Source = AssociatedObject
});
AssociatedObject.OpacityMask = new VisualBrush(border);
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.OpacityMask = null;
}
}
<Style x:Key="BorderWithRoundCornersStyle" TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="50" />
<Setter Property="behaviors:OpacityMaskBehavior.IsEnabledForStyle" Value="True" />
</Style>