c# - 带有图像和填充效果的 WPF 进度条

标签 c# wpf .net-4.5

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

enter image description here

和前景:

enter image description here

想法是创建这样的东西:

enter image description here

我在 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但不能在我的风格中使用它。

最佳答案

我已经成功地创建了具有我想要的效果的样式。 下面是它的样子:

enter image description here

下面是使用样式和 slider 更改进度条值的工作代码:

<?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. 第二个要简单得多,它只使用两个图像(空的和填充的)。当值改变时,填充图像,即在空的顶部,从左或从底部显示。我使用了充满图像的 Canvas 并更改了它的宽度或高度。

我刚开始使用 WPF,所以有人知道更好的解决方案请发布答案。

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

enter image description here enter image description here

关于c# - 带有图像和填充效果的 WPF 进度条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32749115/

相关文章:

c# - WCF 行为配置作为 .NET Remoting

c# - 使用 winform checkbox 进行 linq 查询

c# - 处理 ViewModels 和 CanExecute 处理程序

.net - 当我将目标框架更改为 4.0 时,为什么我的 WPF 3.5 应用程序获得了 app.config 文件?

.net - .net 4.5 中的 c2WTS(对 Windows token 服务的声明)

c# - 为什么此事件日志的 EntryWritten 事件永远不会触发?

c# - 在 WCF 服务中使用语句

.net - 为什么 WinRT 框架程序集与其(不同的)非 WinRT 对应项具有相同的完全限定名称?

c# - 如何将光标置于C#中Datepicker控件的第一个位置?