/// <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;
}
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);
}
}
要测试这一点,只需编译以下两个示例:
<!-- 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>
7条答案
按热度按时间hec6srdp1#
以下是Jobi提到的这个线程的亮点
下面是一个继承自Border的类的实现,并实现了适当的功能:
d5vmydt92#
纯XAML:
**更新:**找到了一个更好的方法来达到同样的效果。现在您也可以将 Border 替换为任何其他元素。
lfapxunr3#
正如Micah提到的,
ClipToBounds
不能与Border.ConerRadius
一起工作。有UIElement.Clip属性,
Border
支持该属性作为子元素。如果你知道边界的确切大小,那么下面是解决方案:
如果大小未知或者是动态的,那么可以使用
Converter
forBorder.Clip
。参见解决方案here。ulydmbyx4#
所以我只是偶然发现了这个解决方案,然后按照Jobi提供的msdn论坛链接,花了20分钟编写了我自己的ClippingBorder控件。
然后我意识到CornerRadius属性类型不是double,而是System.Windows.CornerRaduis,它接受4个double,每个角一个。
所以我现在要列出另一个替代解决方案,这将很可能满足大多数人的要求,他们将在未来偶然发现这篇文章。
假设你有一个XAML,它看起来像这样:
问题是Grid元素的背景会溢出圆角。确保
<Grid>
的背景是透明的,而不是将相同的画笔分配给<Border>
元素的“Background”属性。不再溢出圆角,也不需要一大堆CustomControl代码。理论上,客户区仍然有可能绘制超过角落的边缘,但您可以控制该内容,因此作为开发人员,您应该能够有足够的填充,或者确保边缘旁边的控件的形状是适当的(在我的情况下,我的按钮是圆形的,所以非常适合角落,没有任何问题)。
7d7tgy0s5#
使用@Andrew Mikhailov的解决方案,您可以定义一个简单的类,这使得为每个受影响的元素手动定义
VisualBrush
变得不必要:要测试这一点,只需编译以下两个示例:
rpppsulh6#
将网格变小或边框变大。以便边框元素完全包含网格。
或者,看看你是否可以使网格的背景透明,这样“突出”就不明显了。
**更新:**哎呀,没有注意到这是一个WPF问题。我不熟悉。这是一般的HTML/CSS建议。也许它会有所帮助...
nwlqm0z17#
我不喜欢使用自定义控件。创建了一个行为代替。