Как заставить рамку обрезать дочерние элементы? - PullRequest
16 голосов
/ 13 апреля 2011

У меня есть Border со свойством CornerRadius, установленным на 10. Внутри этого Border есть 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>

Ответы [ 3 ]

20 голосов
/ 13 апреля 2011

Вы можете написать конвертер для свойства 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>
7 голосов
/ 10 декабря 2014

Существует также решение вашей проблемы только на XAML с использованием свойства OpacityMask.Хитрость заключается в том, чтобы создать 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 в качестве обтравочной маски, но он также может быть другим элементом, если его цвет заливки непрозрачен.Также обратите внимание, что клипмаска Граница также имеет тот же CornerRadius.

, вдохновленный: http://www.codeproject.com/Articles/225076/Creating-Inner-Shadows-for-WPF-and-Silverlight

1 голос
/ 13 апреля 2011

ClipToBounds - это свойство, которое может помочь в этом случае.

Редактировать: После некоторого тестирования я заметил, что ClipToBounds заботится только о реальных границах (т. е. прямоугольная область, используемая элементом управления), поэтому контент по-прежнему торчит по углам ...

Похоже, что простое отсечение до границы невозможно .Вы можете установить свойство Clip в прямоугольник со скругленными углами, но это не очень удобно, хотя, я думаю, его размер не может быть ограничен.

В ваших параметрах, похоже, используется OpacityMask вместе с VisualBrush или воссозданием отсечения всякий раз, когда соответствующие свойства изменяются с помощью MultiBinding & MultiValueConverter ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...