6

我需要创建一个圆形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>

这导致:

错误剪辑的图像

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

我需要的是让 thePART_Indicator夹在 上roundBorder,结果如下:

所需剪裁的图像

4

3 回答 3

7

类上有一个ClipToBounds属性应该将内容剪辑到.BorderBorder

<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.RadiusXandRectangle.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命名的...剪辑颜色,ClipRectangle或者当我说这个剪辑时,也许我应该说这应该是剪辑,因为我刚刚发现这似乎只在 WPF 设计器中有效,而不是当应用程序运行。

在此处输入图像描述

但是,我在这里没时间了,所以希望你能找到最后一块拼图并自己完成它。潜在地,您还可以通过将数据绑定到设置为on 的GradientStop.Offseta 的属性来完成此操作,因此您甚至不需要此方法的 a。以后可以的话我再看看。LinearGradientBrushBackgroundBorderRectangle


更新>>>

我又看了一遍,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 之间的值,这将创建您的电平表。

于 2014-06-11T10:35:27.513 回答
6

使用 OpacityMask 更好的解决方案,除了放置在“MainGrid”中的 OuterBorder 之外的所有模板部分都使用 Opacity 蒙版进行剪辑,该蒙版由名为“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>
于 2014-07-09T11:04:04.170 回答
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 的回答)在 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();
    }
} 
于 2014-06-11T12:17:11.527 回答