在 WPF 中裁剪边框
Posted
技术标签:
【中文标题】在 WPF 中裁剪边框【英文标题】:Clipping a border in WPF 【发布时间】:2014-08-01 05:29:18 【问题描述】:我需要创建一个圆形ProgressBar
模板。
控制模板:
<ControlTemplate TargetType="x:Type ProgressBar">
<Grid x:Name="TemplateRoot" SnapsToDevicePixels="true">
<Rectangle x:Name="PART_Track" Margin="1" Fill="White" />
<Border x:Name="PART_Indicator" HorizontalAlignment="Left" Margin="1" >
<Grid x:Name="Foreground" >
<Rectangle x:Name="Indicator" Fill="TemplateBinding Background" />
<Grid x:Name="Animation" ClipToBounds="true" >
<Rectangle x:Name="PART_GlowRect" Fill="#FF86C7EB"
HorizontalAlignment="Left" Margin="-100,0,0,0" Width="100"/>
</Grid>
</Grid>
</Border>
<Border x:Name="roundBorder" BorderBrush="TemplateBinding BorderBrush"
BorderThickness="TemplateBinding BorderThickness" CornerRadius="10" />
<TextBlock />
</Grid>
</ControlTemplate>
这导致:
PART_Indicator
是左侧的 LightBlue 矩形(其宽度在 ProgressBar
控件内部设置,如此处所示,值为 20)和 roundBorder
。
我需要将PART_Indicator
夹在roundBorder
上,结果如下:
【问题讨论】:
检查this 问题。它可以帮助你 顺便说一句,任何人都在看这个问题。下面的答案。遗憾的是,0 票赞成。效果很好。这是要走的路。没有转换器。基于控件的内容对模板没有额外的影响。在保留的同时进行简单的剪辑。 @gt 哪一个? 【参考方案1】:Border
类上有一个ClipToBounds
属性应该在Border
的边界处剪辑内容,但不幸的是,它并没有按照它所说的那样做锡:
<Border CornerRadius="25" BorderBrush="RoyalBlue" BorderThickness="3" Width="300"
Height="50" ClipToBounds="True"> <!-- This doesn't work as expected -->
<Rectangle Fill="SkyBlue" />
</Border>
不过,Rectangle
类也提供了一些可以提供帮助的属性。是否有什么阻止您仅使用Rectangle.RadiusX
和Rectangle.RadiusY
属性来圆角Rectangle
?:
<Border CornerRadius="25" BorderBrush="RoyalBlue" BorderThickness="3" Width="300"
Height="50">
<Rectangle RadiusX="23" RadiusY="23" Fill="SkyBlue" />
</Border>
我知道您想要剪裁 Rectangle
的彩色填充,但您可以使用 Rectangle.Clip
属性:
<Border CornerRadius="25" BorderBrush="RoyalBlue" BorderThickness="3" Width="300"
Height="50">
<Grid>
<Rectangle Name="ClipRectangle" Fill="Green" Margin="50,0,0,0"
Visibility="Hidden" />
<Rectangle RadiusX="23" RadiusY="23" Fill="SkyBlue" Clip="Binding
RenderedGeometry, ElementName=ClipRectangle" />
</Grid>
</Border>
这会将彩色Rectangle
与另一个名为Rectangle
的RenderedGeometry
剪辑在一起,名为ClipRectangle
...或者当我说这个剪辑时,也许我应该说这应该是剪辑,因为我刚刚发现这似乎只在 WPF 设计器中工作,而不是在应用程序运行时工作。
但是,我没时间了,所以希望你能找到最后一块拼图并自己完成。潜在地,您还可以通过将数据绑定到 LinearGradientBrush
的 GradientStop.Offset
属性来完成此操作,该属性设置为 Border
上的 Background
,因此对于此方法,您甚至不需要 Rectangle
。以后可以的话我再看看。
更新>>>
我再次查看了这个Clip Rectangle
,但不明白为什么它只适用于 Visual Studio 设计器。所以,放弃这个想法,你可以试试LinearGradientBrush
的想法,同样不错。首先,定义你的Brush
:
<LinearGradientBrush x:Key="ValueBrush" StartPoint="0,0" EndPoint="1,0">
<GradientStop Offset="0.0" Color="SkyBlue" />
<GradientStop Offset="0.7" Color="SkyBlue" />
<GradientStop Offset="0.7" Color="Transparent" />
<GradientStop Offset="1.0" Color="Transparent" />
</LinearGradientBrush>
现在,我已经硬编码了这些值来生成这个:
仅从这段代码:
<Border CornerRadius="25" BorderBrush="RoyalBlue" Background="StaticResource
ValueBrush" BorderThickness="3" Width="300" Height="50" ClipToBounds="True" />
根据您的实际需求,您需要创建一个double
属性来将数据绑定到GradientStop.Offset
属性,如下所示:
<LinearGradientBrush x:Key="ValueBrush" StartPoint="0,0" EndPoint="1,0">
<GradientStop Offset="0.0" Color="SkyBlue" />
<GradientStop Offset="Binding MidPoint" Color="SkyBlue" />
<GradientStop Offset="Binding MidPoint" Color="Transparent" />
<GradientStop Offset="1.0" Color="Transparent" />
</LinearGradientBrush>
现在,只要您提供介于 0.0 和 1.0 之间的值,这将创建您的电平表。
【讨论】:
这正是我想要的,谢谢。我试试看 我实际上无法让它工作,我会在+1分钟后尝试【参考方案2】:使用 OpacityMask 更好的解决方案,除了放置在“MainGrid”中的 OuterBorder 之外的所有模板部分都使用 Opacity 蒙版进行裁剪,该蒙版由名为“MaskBorder”的对象设置。
“TemplateRoot”存在于 PrograssBar 控件的内部工作中。
<ControlTemplate TargetType="x:Type ProgressBar">
<Grid x:Name="TemplateRoot">
<Border x:Name="OuterBorder" BorderBrush="TemplateBinding BorderBrush" BorderThickness="TemplateBinding BorderThickness" CornerRadius="10">
<Grid>
<Border x:Name="MaskBorder" Background="TemplateBinding Background" CornerRadius="9.5" />
<Grid x:Name="MainGrid">
<Grid.OpacityMask>
<VisualBrush Visual="Binding ElementName=MaskBorder" />
</Grid.OpacityMask>
<Rectangle x:Name="PART_Track" Fill="White" />
<Border x:Name="PART_Indicator" HorizontalAlignment="Left">
<Grid x:Name="Foreground">
<Rectangle x:Name="Indicator" Fill="TemplateBinding Background" />
<Grid x:Name="Animation" ClipToBounds="true">
<Rectangle x:Name="PART_GlowRect" Fill="#FF86C7EB" HorizontalAlignment="Left" Margin="-100,0,0,0" Width="100" />
</Grid>
</Grid>
</Border>
</Grid>
</Grid>
</Border>
</Grid>
</ControlTemplate>
【讨论】:
嗨@Sheridan,我找到了一个比我拥有的解决方案更好的解决方案。【参考方案3】:我最终做了什么:
控制模板:
<ControlTemplate TargetType="x:Type ProgressBar">
<Grid x:Name="TemplateRoot" SnapsToDevicePixels="true">
<Rectangle x:Name="PART_Track" Fill="White" />
<Border x:Name="roundBorder" BorderBrush="TemplateBinding BorderBrush" BorderThickness="TemplateBinding BorderThickness" CornerRadius="10"/>
<Border x:Name="PART_Indicator" HorizontalAlignment="Left">
<Border.Clip>
<MultiBinding Converter="x:Static common:UIConverters.BorderClipConverter">
<Binding Path="ActualWidth" ElementName="roundBorder" />
<Binding Path="ActualHeight" ElementName="roundBorder" />
<Binding Path="CornerRadius" ElementName="roundBorder" />
</MultiBinding>
</Border.Clip>
<Grid x:Name="Foreground">
<Rectangle x:Name="Indicator" Fill="TemplateBinding Background" />
<Grid x:Name="Animation" ClipToBounds="true">
<Rectangle x:Name="PART_GlowRect" Fill="#FF86C7EB" HorizontalAlignment="Left" Margin="-100,0,0,0" Width="100" />
</Grid>
</Grid>
</Border>
</Grid>
</ControlTemplate>
BorderClipConverter:(来自Marat Khasanov answer)在矩形中进行了一些微调
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];
var clip = new RectangleGeometry(new Rect(1.5, 1.5, width - 3, height - 3), 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();
【讨论】:
以上是关于在 WPF 中裁剪边框的主要内容,如果未能解决你的问题,请参考以下文章