Подтвердить что ты не робот

Как сделать границу обрезкой дочерних элементов?

У меня есть свойство 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>
4b9b3361

Ответ 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...