【问题标题】:How to make the border trim the child elements?如何让边框修剪子元素?
【发布时间】:2011-08-04 17:26:10
【问题描述】:

我有一个Border,其中CornerRadius 属性设置为10。在Border 内部,有一个StackPanel。该面板包含两个Borders,分别具有蓝色和红色背景。

蓝色边框的左上角和右上角以及红色边框的左下角和右下角伸出第一个边框的弯曲边缘。我希望将蓝色和红色边框修剪到父边框。那可能吗?

顺便说一句,我知道如果我为蓝色和红色边框的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>

【问题讨论】:

  • 你能发布一些说明问题的代码吗?

标签: wpf


【解决方案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>

【讨论】:

  • 我能找到的最好的例子!
  • 我想过做这样的事情,但想知道是否有一种方便的 XAML 方式来这样做。我会试试这个。我的问题:stackoverflow.com/questions/24158147/wpf-clipping-a-border
  • 这可以通过常规转换器(即不是多值转换器)然后绑定到自身来完成。它会使绑定更漂亮(即更容易重复使用),并将抓取宽度/高度/半径的逻辑推入转换器。
  • @claudekennilol,不能同意你的观点,因为将此逻辑推送到转换器需要实现属性更改侦听器,这是非常重要的任务。
  • 这是一个好点,具体取决于内容。问题中给出的示例和许多其他用途不会有这个问题,但肯定有一些会。
【解决方案2】:

还可以使用OpacityMask 属性为您的问题提供仅XAML 的解决方案。诀窍是在外边框内创建一个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>

在上面的 sn-p 中,我使用了 Border 作为剪贴蒙版,但它也可以是另一个元素,只要它的填充颜色不透明。另请注意,clipMask 边框也具有相同的CornerRadius

灵感来自:http://www.codeproject.com/Articles/225076/Creating-Inner-Shadows-for-WPF-and-Silverlight

【讨论】:

    【解决方案3】:

    ClipToBounds 是在这种情况下可能有帮助的属性。

    编辑:经过一些测试,我注意到 ClipToBounds 只关心实际边界(即控件使用的矩形区域),所以内容仍然突出在角落...

    这似乎表明简单的边框裁剪是不可能的。您可以将Clip 属性设置为圆角矩形,但这不是很方便,因为我认为它的大小无法绑定。

    您的选择似乎是使用 OpacityMask 和 VisualBrush 或在相关属性更改时使用 MultiBinding 和 MultiValueConverter 重新创建剪辑...

    【讨论】:

    • OpacticyMask 仅几何类型除外,因此您仍然需要一些转换器,例如 @MaratKhasanov 的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-20
    相关资源
    最近更新 更多