Как сделать границу обрезкой дочерних элементов?
У меня есть свойство Border
с CornerRadius
, установленное в 10. Внутри этого Border
есть a StackPanel
. Панель содержит два Border
с синим и красным фоном, соответственно.
Верхний левый и верхний правый углы синей границы и нижний левый и правый нижние углы красной границы торчат из изогнутых краев первой границы. Я хочу, чтобы синяя и красная границы были отделены от родительской границы. Это возможно?
Кстати, я знаю, что если бы я установил одно и то же значение для свойства
CornerRadius
синей и красной границ, он будет следовать кривой первого. Я не хочу этого - я хочу обрезки. Спасибо!
<Border
Width="200"
Height="200"
BorderThickness="1"
BorderBrush="Black"
CornerRadius="10">
<StackPanel>
<Border Height="100" Background="Blue" />
<Border Height="100" Background="Red" />
</StackPanel>
</Border>
Ответы
Ответ 1
Вы можете написать конвертер для свойства Clip. Конвертер должен реализовывать IMultiValueConverter и привязан к фактическому размеру и радиусу угла, например.
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();
}
}
Использование:
<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>
Ответ 2
Там также есть решение XAML для вашей проблемы, используя свойство OpacityMask
. Фокус в том, чтобы создать Grid
внутри внешней границы и установить Grid OpacityMask другому элементу, который действует как обтравочная маска.
<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>
В вышеприведенном фрагменте я использовал Border
как обтравочную маску, но также может быть другим элементом, если его цвет заливки непрозрачен. Также обратите внимание, что clipMask Border также имеет те же CornerRadius
.
Вдохновленный: http://www.codeproject.com/Articles/225076/Creating-Inner-Shadows-for-WPF-and-Silverlight
Ответ 3
ClipToBounds
- это свойство, которое может помочь в этом случае.
Изменить: После некоторого тестирования я заметил, что ClipToBounds заботится только о фактических границах (т.е. о прямоугольной области, которую использует элемент управления), поэтому контент по-прежнему торчит по углам...
Это похоже на то, что простое обрезание на границе невозможно. Вы можете установить свойство Clip
в округленный прямоугольник, это не очень удобно, потому что его размер не может быть привязан, я думаю.
Ваши параметры, кажется, используют OpacityMask
вместе с VisualBrush или воссоздают отсечение при изменении соответствующих свойств с помощью MultiBinding и MultiValueConverter...