在WPF中剪切边框

时间:2014-06-11 08:30:52

标签: wpf clipping clip opacitymask

我需要创建一个圆ProgressBar模板。

ControlTemplate:

<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>

这导致:

image of incorrect clipping

其中PART_Indicator是左边的LightBlue矩形(其宽度在ProgressBar控件内部设置,如此处所示,值为20)和roundBorder

我需要的是PART_Indicator剪切roundBorder,结果如下:

image of desired clipping

3 个答案:

答案 0 :(得分:5)

ClipToBounds类上有一个Border属性,应该Border的范围内剪切内容,但不幸的是,它没有#39} ; t&#39;做它在锡上的说法:

<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.RadiusXRectangle.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与名为RenderedGeometry的其他Rectangle的{​​{1}}剪辑...或当我说此剪辑时,也许我应该说这应该剪辑,因为我发现这只能在WPF Designer中运行,而不是在应用程序运行时。

enter image description here

但是,我没有时间在这里,所以希望你能找到拼图的最后一块并自己完成。潜在地,您也可以通过数据绑定到ClipRectangle的{​​{1}}属性来完成此操作,该属性设置为GradientStop.Offset上的LinearGradientBrush,因此您不会这个方法甚至需要Background。如果我以后可以再看看。


更新&gt;&gt;&gt;

我再次查看了这个Border,并且无法解释为什么它只适用于Visual Studio Designer。所以,放弃这个想法,你可以尝试Rectangle想法,这同样是好的。首先,定义您的Clip Rectangle

LinearGradientBrush

现在,我已经将这些值硬编码以产生这个:

enter image description here

仅从此代码:

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

现在,只要您提供介于0.0和1.0之间的值,就会创建您的电平表。

答案 1 :(得分:3)

使用OpacityMask更好的解决方案,除了放置在“MainGrid”中的OuterBorder之外的所有模板部件都使用不透明蒙板进行剪裁,该掩码由一个名为“MaskBorder”的对象设置。

对于PrograssBar控件的内部工作,存在

“TemplateRoot”。

  <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>

答案 2 :(得分:2)

我最终做了什么:

ControlTemplate:

         <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)并在Rect

中进行了一些微调
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();
    }
}