带有图像和填充效果的WPF Progressbar

时间:2015-09-23 20:43:02

标签: c# wpf .net-4.5

我想创建自定义进度条样式,从底部显示图像填充。 我创建了两个图片,背景:

enter image description here

和前景:

enter image description here

想法是创造这样的东西:

enter image description here

Inside Blend我创造了这种风格:

<Style x:Key="ImageFill" TargetType="{x:Type ProgressBar}">
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ProgressBar}">
                <Grid x:Name="TemplateRoot" SnapsToDevicePixels="true">
                    <Image x:Name="PART_Track" Source="Play_Background.png" Margin="1" Stretch="Fill"/>
                    <Rectangle x:Name="PART_Indicator" Margin="1" HorizontalAlignment="Left" Fill="#FFD6931C">
                        <Rectangle.OpacityMask>
                                    <RadialGradientBrush>
                                <GradientStop Color="Black" Offset="0.87"/>
                                <GradientStop Color="Transparent" Offset="0.87"/>
                            </RadialGradientBrush>
                        </Rectangle.OpacityMask>
                    </Rectangle>
                    <Image Source="Play_Foreground.png" Margin="1" Stretch="Fill"/>
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

但是当设定值为60时,我得到了这个:

enter image description here

我可以将OpacitMmask更改为:

<RadialGradientBrush Center="106,104" GradientOrigin="60,60" MappingMode="Absolute" RadiusY="97" RadiusX="98">
    <GradientStop Color="Black" Offset="0.87"/>
    <GradientStop Color="Transparent" Offset="0.87"/>
</RadialGradientBrush>

但是当我调整进度条的大小时,我会得到不必要的行为:

enter image description here

如何解决这个问题?我需要掩码将MappingMode设置为RelativeToBoundingBox,这样我就可以设置不同的大小到进度条。

以下是我在Blend中生成的完整XAML:

<Window x:Class="ImageProgressBar.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="389" Width="523">
    <Window.Resources>
<Style x:Key="ImageFill" TargetType="{x:Type ProgressBar}">
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ProgressBar}">
                <Grid x:Name="TemplateRoot" SnapsToDevicePixels="true">
                    <Image x:Name="PART_Track" Source="Play_Background.png" Margin="1" Stretch="Fill"/>
                    <Rectangle x:Name="PART_Indicator" Margin="1" HorizontalAlignment="Left" Fill="#FFD6931C">
                        <Rectangle.OpacityMask>
                            <RadialGradientBrush Center="106,104" GradientOrigin="60,60" MappingMode="Absolute" RadiusY="97" RadiusX="98">
                                <GradientStop Color="Black" Offset="0.87"/>
                                <GradientStop Color="Transparent" Offset="0.87"/>
                            </RadialGradientBrush>
                        </Rectangle.OpacityMask>
                    </Rectangle>
                    <Image Source="Play_Foreground.png" Margin="1" Stretch="Fill"/>
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
    </Window.Resources>
    <Grid>
        <ProgressBar 
        Maximum="{Binding ElementName=MySlider, Path=Maximum, Mode=TwoWay}" Minimum="{Binding ElementName=MySlider, Path=Minimum, Mode=TwoWay}" Value="{Binding ElementName=MySlider, Path=Value, Mode=TwoWay}"
        HorizontalAlignment="Left" Height="200" Margin="10,10,0,0" VerticalAlignment="Top" Width="200" Style="{DynamicResource ImageFill}"/>

                <ProgressBar 
        Maximum="{Binding ElementName=MySlider, Path=Maximum, Mode=TwoWay}" Minimum="{Binding ElementName=MySlider, Path=Minimum, Mode=TwoWay}" Value="{Binding ElementName=MySlider, Path=Value, Mode=TwoWay}"
        HorizontalAlignment="Left" Height="100" Margin="294,10,0,0" VerticalAlignment="Top" Width="100" Style="{DynamicResource ImageFill}"/>

        <Slider  Name="MySlider" HorizontalAlignment="Left" Margin="10,215,0,0" VerticalAlignment="Top" Width="200" Minimum="0" Maximum="100" Value="0"/>

    </Grid>
</Window>

我找到了http://vbcity.com/blogs/xtab/archive/2009/11/24/wpf-controltemplates-creating-a-non-rectangular-progressbar.aspx,但不能在我的风格中使用它。

2 个答案:

答案 0 :(得分:5)

我设法创造了我想要的效果。 以下是它的外观:

enter image description here

及以下是使用样式和滑块的工作代码来更改进度条的值:

<?xml version="1.0" encoding="UTF-8"?>
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ImageProgressBar.MainWindow" Title="ProgressBar Image Fill" Height="284" Width="598" Background="#FFEAE0E0">
   <Window.Resources>
      <Style x:Key="ImageFill" TargetType="{x:Type ProgressBar}">
         <Setter Property="Template">
            <Setter.Value>
               <ControlTemplate TargetType="{x:Type ProgressBar}">
                  <Grid x:Name="TemplateRoot" SnapsToDevicePixels="true">
                     <Image x:Name="PART_Track" Source="Play_Background.png" Margin="1" Stretch="Fill" />
                     <Rectangle x:Name="PART_Indicator" Margin="1" HorizontalAlignment="Left" Fill="{TemplateBinding Foreground}">
                        <Rectangle.OpacityMask>
                           <RadialGradientBrush Center="106,104" GradientOrigin="60,60" MappingMode="Absolute" RadiusY="97" RadiusX="98">
                              <GradientStop Color="Black" Offset="0.87" />
                              <GradientStop Color="Transparent" Offset="0.87" />
                           </RadialGradientBrush>
                        </Rectangle.OpacityMask>
                     </Rectangle>
                     <Image Source="Play_Foreground.png" Margin="1" Stretch="Fill" />
                  </Grid>
                  <ControlTemplate.Triggers>
                     <!-- Getting vertical style working using technique described here: http://stackoverflow.com/a/6849237/7532 -->
                     <Trigger Property="Orientation" Value="Vertical">
                        <Setter TargetName="PART_Indicator" Property="LayoutTransform">
                           <Setter.Value>
                              <RotateTransform Angle="270" />
                           </Setter.Value>
                        </Setter>
                        <Setter TargetName="PART_Indicator" Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Height}" />
                        <Setter TargetName="PART_Indicator" Property="Height" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Width}" />
                        <Setter TargetName="PART_Indicator" Property="VerticalAlignment" Value="Bottom" />
                     </Trigger>
                  </ControlTemplate.Triggers>
               </ControlTemplate>
            </Setter.Value>
         </Setter>
      </Style>
      <Style x:Key="SimpleImageFill" TargetType="{x:Type ProgressBar}">
         <Setter Property="Template">
            <Setter.Value>
               <ControlTemplate TargetType="{x:Type ProgressBar}">
                  <Grid x:Name="TemplateRoot" SnapsToDevicePixels="true">
                     <Image x:Name="PART_Track" Source="Play_Game_Empty.png" />
                     <Canvas ClipToBounds="True" x:Name="PART_Indicator" HorizontalAlignment="Left">
                        <Image x:Name="Image_Fill" Source="Play_Game_Fill.png"
                        Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Width}"
                        Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Height}" />
                     </Canvas>
                  </Grid>
                  <ControlTemplate.Triggers>
                     <Trigger Property="Orientation" Value="Vertical">
                        <Setter TargetName="PART_Indicator" Property="LayoutTransform">
                           <Setter.Value>
                              <RotateTransform Angle="270" />
                           </Setter.Value>
                        </Setter>
                        <Setter TargetName="Image_Fill" Property="LayoutTransform">
                           <Setter.Value>
                              <RotateTransform Angle="-270" />
                           </Setter.Value>
                        </Setter>
                        <Setter TargetName="PART_Indicator" Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Height}" />
                        <Setter TargetName="PART_Indicator" Property="Height" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Width}" />
                        <Setter TargetName="PART_Indicator" Property="VerticalAlignment" Value="Bottom" />
                     </Trigger>
                  </ControlTemplate.Triggers>
               </ControlTemplate>
            </Setter.Value>
         </Setter>
      </Style>
   </Window.Resources>
   <Grid>
      <ProgressBar Foreground="Orange" Orientation="Vertical" Maximum="{Binding ElementName=MySlider, Path=Maximum, Mode=TwoWay}" Minimum="{Binding ElementName=MySlider, Path=Minimum, Mode=TwoWay}" Value="{Binding ElementName=MySlider, Path=Value, Mode=TwoWay}" HorizontalAlignment="Left" Height="200" Margin="10,10,0,0" VerticalAlignment="Top" Width="200" Style="{DynamicResource ImageFill}" />
      <ProgressBar Maximum="{Binding ElementName=MySlider, Path=Maximum, Mode=TwoWay}" Minimum="{Binding ElementName=MySlider, Path=Minimum, Mode=TwoWay}" Value="{Binding ElementName=MySlider, Path=Value, Mode=TwoWay}" HorizontalAlignment="Left" Height="200" Margin="227.5,10,0,0" VerticalAlignment="Top" Width="200" Style="{DynamicResource ImageFill}" />
      <Slider Name="MySlider" HorizontalAlignment="Left" Margin="10,215,0,0" VerticalAlignment="Top" Width="200" Minimum="0" Maximum="100" Value="0" />
      <ProgressBar Orientation="Vertical" Maximum="{Binding ElementName=MySlider, Path=Maximum, Mode=TwoWay}" Minimum="{Binding ElementName=MySlider, Path=Minimum, Mode=TwoWay}" Value="{Binding ElementName=MySlider, Path=Value, Mode=TwoWay}" HorizontalAlignment="Left" Height="150" Margin="432.5,10,0,0" VerticalAlignment="Top" Width="150" Style="{DynamicResource SimpleImageFill}" />
   </Grid>
</Window>

我实际上创造了两种风格:

  1. 第一个是使用两个图像(我的问题中的前两个)和圆圈 它们之间。想法是从底部或左边填充圆圈。 圆圈充满了前景色。
  2. 第二个更简单,它只使用两个图像(空和填充)。当值变化时,填充图像(位于空白之上)从左侧或底部显示。我使用的是充满图像的画布,我改变它的宽度或高度。
  3. 我刚刚开始使用WPF,所以有人知道更好的解决方案请发帖回答。

    下面我添加了第二个样式使用的两个图像应用于第三个进度条。

    enter image description here enter image description here

答案 1 :(得分:0)

检查出来WPF: Anchor points don't work well sometimes问题是你的大小和边距绝对不是你控件的大小。