我有一个带有圆角的边框元素,包含一个3x3网格。网格的角落伸出边界。我该如何解决这个问题?我尝试使用ClipToBounds但没有得到任何结果。 谢谢你的帮助
答案 0 :(得分:52)
以下是thread
提到的Jobi的重点这是一个继承自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;
}
答案 1 :(得分:40)
Pure 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>
<强>更新强> 找到了实现相同结果的更好方法。您现在也可以将 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>
答案 2 :(得分:7)
所以我刚刚遇到了这个解决方案,然后进入了Jobi提供的msdn论坛链接,花了20分钟编写我自己的ClippingBorder控件。
然后我意识到CornerRadius属性类型不是double,而是System.Windows.CornerRaduis,它接受4个双打,每个角落一个。
所以我现在要列出另一种替代解决方案,这很可能会满足大多数将来偶然发现这篇文章的人的要求......
假设您有XAML,如下所示:
<Border CornerRadius="10">
<Grid>
... your UI ...
</Grid>
</Border>
问题是Grid元素的背景渗透并显示过去的圆角。确保您的<Grid>
具有透明背景,而不是将同一笔刷分配给<Border>
元素的“背景”属性。没有更多的流血过去,也不需要一大堆CustomControl代码。
理论上,客户区域仍有可能超越角落边缘,但您可以控制该内容,因此您作为开发人员应该能够拥有足够的填充,或者确保控件的形状在边缘旁边是合适的(在我的情况下,我的按钮是圆的,所以非常适合在角落没有任何问题)。
答案 3 :(得分:7)
正如Micah所说,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>
如果尺寸未知或动态,则可以使用Converter
的{{1}}。请参阅解决方案here。
答案 4 :(得分:2)
使用@Andrew Mikhailov的解决方案,您可以定义一个简单的类,这样就可以手动为每个受影响的元素定义VisualBrush
:
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>
答案 5 :(得分:0)
使网格更小或边框更大。这样border元素就完全包含了网格。
或者看看你是否可以使网格的背景透明,以便“伸出”不明显。
更新:哎呀,没注意到这是一个WPF问题。我不熟悉。这是一般的HTML / CSS建议。也许它有帮助...
答案 6 :(得分:0)
我不喜欢使用自定义控件。而是创建了一个行为。
using System.Linq;
using System.Windows;
using System.Windows.Interactivity;
/// <summary>
/// Base class for behaviors that could be used in style.
/// </summary>
/// <typeparam name="TComponent">Component type.</typeparam>
/// <typeparam name="TBehavior">Behavior type.</typeparam>
public class AttachableForStyleBehavior<TComponent, TBehavior> : Behavior<TComponent>
where TComponent : System.Windows.DependencyObject
where TBehavior : AttachableForStyleBehavior<TComponent, TBehavior>, new()
{
#pragma warning disable SA1401 // Field must be private.
/// <summary>
/// IsEnabledForStyle attached property.
/// </summary>
public static DependencyProperty IsEnabledForStyleProperty =
DependencyProperty.RegisterAttached("IsEnabledForStyle", typeof(bool),
typeof(AttachableForStyleBehavior<TComponent, TBehavior>), new FrameworkPropertyMetadata(false, OnIsEnabledForStyleChanged));
#pragma warning restore SA1401
/// <summary>
/// Sets IsEnabledForStyle value for element.
/// </summary>
public static void SetIsEnabledForStyle(UIElement element, bool value)
{
element.SetValue(IsEnabledForStyleProperty, value);
}
/// <summary>
/// Gets IsEnabledForStyle value for element.
/// </summary>
public static bool GetIsEnabledForStyle(UIElement element)
{
return (bool)element.GetValue(IsEnabledForStyleProperty);
}
private static void OnIsEnabledForStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement uie = d as UIElement;
if (uie != null)
{
var behColl = Interaction.GetBehaviors(uie);
var existingBehavior = behColl.FirstOrDefault(b => b.GetType() ==
typeof(TBehavior)) as TBehavior;
if ((bool)e.NewValue == false && existingBehavior != null)
{
behColl.Remove(existingBehavior);
}
else if ((bool)e.NewValue == true && existingBehavior == null)
{
behColl.Add(new TBehavior());
}
}
}
}
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
/// <summary>
/// Behavior that creates opacity mask brush.
/// </summary>
internal class OpacityMaskBehavior : AttachableForStyleBehavior<Border, OpacityMaskBehavior>
{
protected override void OnAttached()
{
base.OnAttached();
var border = new Border()
{
Background = Brushes.Black,
SnapsToDevicePixels = true,
};
border.SetBinding(Border.CornerRadiusProperty, new Binding()
{
Mode = BindingMode.OneWay,
Path = new PropertyPath("CornerRadius"),
Source = AssociatedObject
});
border.SetBinding(FrameworkElement.HeightProperty, new Binding()
{
Mode = BindingMode.OneWay,
Path = new PropertyPath("ActualHeight"),
Source = AssociatedObject
});
border.SetBinding(FrameworkElement.WidthProperty, new Binding()
{
Mode = BindingMode.OneWay,
Path = new PropertyPath("ActualWidth"),
Source = AssociatedObject
});
AssociatedObject.OpacityMask = new VisualBrush(border);
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.OpacityMask = null;
}
}
<Style x:Key="BorderWithRoundCornersStyle" TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="50" />
<Setter Property="behaviors:OpacityMaskBehavior.IsEnabledForStyle" Value="True" />
</Style>