I have a Border
with CornerRadius
property set to 10. Inside that Border
, there's a StackPanel
. The panel contains two Border
s with blue and red backgrounds, respectively.
The upper left and upper right corners of the blue border and the lower left and lower right corners of the red border are sticking out of the curved edges of the first border. I wish to make the blue and red borders trim to the parent border. Is that possible?
By the way, I do know that if I set the same value for CornerRadius
property of the blue and red borders, it will follow the curve of the first one. I don't want that - I want trimming. Thanks!
<Border Width="200" Height="200" BorderThickness="1" BorderBrush="Black" CornerRadius="10"> <StackPanel> <Border Height="100" Background="Blue" /> <Border Height="100" Background="Red" /> </StackPanel> </Border>
You may write a converter for the Clip property. Converter should implement IMultiValueConverter and bound to actual size and corner radius, for example.
public class BorderClipConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values.Length == 3 && values[0] is double && values[1] is double && values[2] is CornerRadius) { var width = (double)values[0]; var height = (double)values[1]; if (width < Double.Epsilon || height < Double.Epsilon) { return Geometry.Empty; } var radius = (CornerRadius)values[2]; // Actually we need more complex geometry, when CornerRadius has different values. // But let me not to take this into account, and simplify example for a common value. var clip = new RectangleGeometry(new Rect(0, 0, width, height), radius.TopLeft, radius.TopLeft); clip.Freeze(); return clip; } return DependencyProperty.UnsetValue; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotSupportedException(); } }
Usage:
<Border CornerRadius="10"> <Border.Clip> <MultiBinding Converter="{StaticResource BorderClipConverter}"> <Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/> <Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}"/> <Binding Path="CornerRadius" RelativeSource="{RelativeSource Self}"/> </MultiBinding> </Border.Clip> </Border>
There's also a XAML-only solution to your problem by using the OpacityMask
property. The trick is to create a Grid
inside the outer Border and set the Grid's OpacityMask to another element that acts as a clipping mask.
<Border Width="200" Height="200" BorderThickness="1" BorderBrush="Black" CornerRadius="10"> <Grid> <Grid.OpacityMask> <VisualBrush Visual="{Binding ElementName=clipMask}" Stretch="None" /> </Grid.OpacityMask> <Border x:Name="clipMask" Background="White" CornerRadius="10" /> <StackPanel Background="White"> <Border Height="100" Background="Blue" /> <Border Height="100" Background="Red" /> </StackPanel> </Grid> </Border>
In the snippet above I used a Border
as clipping mask, but it can also be another element as long as its fill color is non-transparent. Note also that the clipMask Border also has the same CornerRadius
.
Inspired by: http://www.codeproject.com/Articles/225076/Creating-Inner-Shadows-for-WPF-and-Silverlight
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With