如何制作圆角边框的内容也是圆角的?

Gus*_*nti 51 wpf

我有一个带有圆角的边框元素,包含一个3x3网格.网格的角落伸出边界.我该如何解决这个问题?我尝试使用ClipToBounds但没有得到任何结果.谢谢你的帮助

Mic*_*cah 57

以下是Jobi提到的这个主题的亮点

  • 没有装饰器(即边框)或布局面板(即Stackpanel)具有开箱即用的这种行为.
  • ClipToBounds用于布局.ClipToBounds不会阻止元素在其边界之外绘制; 它只是防止儿童的布局"溢出".此外,大多数元素都不需要ClipToBounds = True,因为它们的实现不允许其内容的布局溢出.最值得注意的例外是Canvas.
  • 最后,Border将圆角视为其布局边界内的绘图.

这是一个继承自Border并实现适当功能的类的实现:

     /// <Remarks>
    ///     As a side effect ClippingBorder will surpress any databinding or animation of 
    ///         its childs UIElement.Clip property until the child is removed from ClippingBorder
    /// </Remarks>
    public class ClippingBorder : Border {
        protected override void OnRender(DrawingContext dc) {
            OnApplyChildClip();            
            base.OnRender(dc);
        }

        public override UIElement Child 
        {
            get
            {
                return base.Child;
            }
            set
            {
                if (this.Child != value)
                {
                    if(this.Child != null)
                    {
                        // Restore original clipping
                        this.Child.SetValue(UIElement.ClipProperty, _oldClip);
                    }

                    if(value != null)
                    {
                        _oldClip = value.ReadLocalValue(UIElement.ClipProperty);
                    }
                    else 
                    {
                        // If we dont set it to null we could leak a Geometry object
                        _oldClip = null;
                    }

                    base.Child = value;
                }
            }
        }

        protected virtual void OnApplyChildClip()
        {
            UIElement child = this.Child;
            if(child != null)
            {
                _clipRect.RadiusX = _clipRect.RadiusY = Math.Max(0.0, this.CornerRadius.TopLeft - (this.BorderThickness.Left * 0.5));
                _clipRect.Rect = new Rect(Child.RenderSize);
                child.Clip = _clipRect;
            }
        }

        private RectangleGeometry _clipRect = new RectangleGeometry();
        private object _oldClip;
    }
Run Code Online (Sandbox Code Playgroud)


And*_*lov 42

纯XAML:

<Border CornerRadius="30" Background="Green">
    <Border.OpacityMask>
        <VisualBrush>
            <VisualBrush.Visual>
                <Border 
                    Background="Black"
                    SnapsToDevicePixels="True"
                    CornerRadius="{Binding CornerRadius, RelativeSource={RelativeSource AncestorType=Border}}"
                    Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Border}}"
                    Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Border}}"
                    />
            </VisualBrush.Visual>
        </VisualBrush>
    </Border.OpacityMask>
    <TextBlock Text="asdas das d asd a sd a sda" />
</Border>
Run Code Online (Sandbox Code Playgroud)

更新: 找到一种更好的方法来实现相同的结果.您现在也可以用任何其他元素替换Border.

<Grid>
    <Grid.OpacityMask>
        <VisualBrush Visual="{Binding ElementName=Border1}" />
    </Grid.OpacityMask>
    <Border x:Name="Border1" CornerRadius="30" Background="Green" />
    <TextBlock Text="asdas das d asd a sd a sda" />
</Grid>
Run Code Online (Sandbox Code Playgroud)

例

  • 第一个示例更通用,因为它可以是透明的(剪切形状不必是可见的,带有背景)。 (2认同)

Art*_*tru 8

正如弥迦所说,ClipToBounds不会合作Border.ConerRadius.

UIElement.Clip属性,它Border继承.

如果您知道边框的确切大小,那么这是解决方案:

<Border Background="Blue" CornerRadius="3" Height="100" Width="100">
      <Border.Clip>
        <RectangleGeometry RadiusX="3" RadiusY="3" Rect="0,0,100,100"/>
      </Border.Clip>
      <Grid Background="Green"/>
</Border>
Run Code Online (Sandbox Code Playgroud)

如果尺寸是未知的或动态然后ConverterBorder.Clip可以使用.请参见该解决方案在这里.


DXM*_*DXM 7

所以我刚刚遇到了这个解决方案,然后进入了Jobi提供的msdn论坛链接,花了20分钟编写我自己的ClippingBorder控件.

然后我意识到CornerRadius属性类型不是double,而是System.Windows.CornerRaduis,它接受4个双精度数,每个角落一个.

所以我现在要列出另一种替代解决方案,这很可能满足大多数人将来偶然发现这个帖子的要求......

假设您有XAML,如下所示:

<Border CornerRadius="10">
    <Grid>
        ... your UI ...
    </Grid>
</Border>
Run Code Online (Sandbox Code Playgroud)

问题是Grid元素的背景渗透并显示过去的圆角.确保您<Grid>具有透明背景,而不是将相同的画笔分配给<Border>元素的"背景"属性.不再流失角落,也不需要一大堆CustomControl代码.

确实,从理论上讲,客户区仍然有可能超越角落的边缘,但是您可以控制该内容,因此您作为开发人员应该能够有足够的填充,或者确保控件的形状在旁边边缘是合适的(在我的情况下,我的按钮是圆的,所以非常适合在角落没有任何问题).


小智 5

使用 @Andrew Mikhailov 的解决方案,您可以定义一个简单的类,这使得VisualBrush无需手动为每个受影响的元素定义 a :

public class ClippedBorder : Border
{
    public ClippedBorder() : base()
    {
        var e = new Border()
        {
            Background = Brushes.Black,
            SnapsToDevicePixels = true,
        };
        e.SetBinding(Border.CornerRadiusProperty, new Binding()
        {
            Mode = BindingMode.OneWay,
            Path = new PropertyPath("CornerRadius"),
            Source = this
        });
        e.SetBinding(Border.HeightProperty, new Binding()
        {
            Mode = BindingMode.OneWay,
            Path = new PropertyPath("ActualHeight"),
            Source = this
        });
        e.SetBinding(Border.WidthProperty, new Binding()
        {
            Mode = BindingMode.OneWay,
            Path = new PropertyPath("ActualWidth"),
            Source = this
        });

        OpacityMask = new VisualBrush(e);
    }
}
Run Code Online (Sandbox Code Playgroud)

要测试这一点,只需编译以下两个示例:

<!-- You should see a blue rectangle with rounded corners/no red! -->
<Controls:ClippedBorder
    Background="Red"
    CornerRadius="10"
    Height="425"
    HorizontalAlignment="Center"
    VerticalAlignment="Center"
    Width="425">
    <Border Background="Blue">
    </Border>
</Controls:ClippedBorder>

<!-- You should see a blue rectangle with NO rounded corners/still no red! -->
<Border
    Background="Red"
    CornerRadius="10"
    Height="425"
    HorizontalAlignment="Center"
    VerticalAlignment="Center"
    Width="425">
    <Border Background="Blue">
    </Border>
</Border>
Run Code Online (Sandbox Code Playgroud)