WPF中的进度条样式过时了。如何实现具有Windows Vista或Windows 7阴影发光效果的进度条?

5

WPF中的进度条样式有些老旧。它们是逐步增加的。如何实现带有Vista或Windows 7阴影光晕效果的进度条?

图片 http://quickshare.my3gb.com/download/2.JPG

即使查看了ProgressBar的属性,但是没有与光晕效果相关的属性。

此外,是否有任何与普通进度条不同的动画或其他东西?

编辑

代码:

<ProgressBar Height="41" HorizontalAlignment="Left"    Margin="372,215,0,0" Name="progressBar1" VerticalAlignment="Top" Width="150">
            
</ProgressBar>

1
我认为你需要在Windows 7中使用Aero主题(Windows 7基本版或Windows 7)才能获得平滑的发光增量。如果你切换到Windows经典主题,那么你会得到条形进度条。如果你因某种原因想要在非Aero状态下也有平滑的进度条主题,那么你可以复制定义了Aero状态下“外观”的进度条模板。 - Colin Smith
我尝试更改样式(主题),甚至尝试了Win 8!但应用程序仍然显示传统的工具栏。 - now he who must not be named.
Glow特效已经从Windows 8中移除了...他们正在放弃大部分Aero外观。至于Windows XP SP3,它没有Aero...使用我向你展示的链接之一来强制WPF使用自己的Aero主题,无论你在哪个操作系统上。 - Colin Smith
[重复] (https://dev59.com/XG445IYBdhLWcg3wg6xn) - Bob Vale
这个回答解决了你的问题吗?WPF进度条样式为什么很粗糙? - StayOnTarget
显示剩余6条评论
4个回答

11

自己动手并不难。

创建一个用户控件,具有标准进度条的属性。

Value
Maximum
Minimum

您可以创建一个派生属性,通过使用公式计算出该条形杆的大小:

ProgressBarWidth = (Value / (Maximum + Minimum) * ControlWidth) - Padding

当值、最大值或最小值被更新时会发生变化

将此绑定到进度条控件模板中的“bar”的宽度 - 这样当值属性更新时,进度条将重新调整大小。

进度条的外观取决于您的需要,但我猜你只是想要一堆花哨的填充/渐变/发光效果 - 您可以在Blend中添加这些效果

免责声明:公式可能不正确!

如果你想自己试试,请看看我刚刚创建的一个似乎可以正常工作的例子

public partial class MyProgressBar : UserControl
    {
        public MyProgressBar()
        {
            InitializeComponent();

            Loaded += new RoutedEventHandler(MyProgressBar_Loaded);
        }

        void MyProgressBar_Loaded(object sender, RoutedEventArgs e)
        {
            Update();
        }

        private static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(MyProgressBar), new PropertyMetadata(100d, OnMaximumChanged));
        public double Maximum
        {
            get { return (double)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }


        private static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(MyProgressBar), new PropertyMetadata(0d, OnMinimumChanged));
        public double Minimum
        {
            get { return (double)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }

        private static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(MyProgressBar), new PropertyMetadata(50d, OnValueChanged));
        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }



        private static readonly DependencyProperty ProgressBarWidthProperty = DependencyProperty.Register("ProgressBarWidth", typeof(double), typeof(MyProgressBar), null);
        private double ProgressBarWidth
        {
            get { return (double)GetValue(ProgressBarWidthProperty); }
            set { SetValue(ProgressBarWidthProperty, value); }
        }

        static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            (o as MyProgressBar).Update();
        }

        static void OnMinimumChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            (o as MyProgressBar).Update();
        }

        static void OnMaximumChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            (o as MyProgressBar).Update();
        }


        void Update()
        {
            // The -2 is for the borders - there are probably better ways of doing this since you
            // may want your template to have variable bits like border width etc which you'd use
            // TemplateBinding for
            ProgressBarWidth = Math.Min((Value / (Maximum + Minimum) * this.ActualWidth) - 2, this.ActualWidth - 2);


        }          
    }

XAML

<UserControl x:Class="WpfApplication1.MyProgressBar"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" x:Name="uc">
    <Grid>
        <Border Background="White">
            <Border BorderBrush="Gray" BorderThickness="1">
                <Grid>
                    <Grid.Background>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="#FFE5E5E5" Offset="0" />
                            <GradientStop Color="White" Offset="1" />
                        </LinearGradientBrush>
                    </Grid.Background>
                    <Grid Width="{Binding ProgressBarWidth, ElementName=uc}" HorizontalAlignment="Left">
                        <Grid.Background>
                            <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                                <GradientStop Color="#FFCBFFD0" Offset="0" />
                                <GradientStop Color="#FF62EF73" Offset="1" />
                                <GradientStop Color="#FFAEE56D" Offset="0.39" />
                            </LinearGradientBrush>
                        </Grid.Background>
                    </Grid>
                </Grid>
            </Border>
        </Border>
    </Grid>
</UserControl>

结果:

进度条...自制!

就像我说的,这样的东西相当容易,但仍要考虑重新定义模板或使用原始模板,因为它确实支持正确操作系统上的发光效果。

在我添加了“百分比”依赖属性并在控件模板中绑定到该属性之后,它变成了这个样子:

带数字的自制

更新Percent的代码是

   Percentage = Math.Min((int)(Value / (Maximum + Minimum) * 100), 100);

编辑2:

我调整了填充,并添加了一个白色的内边框,使它看起来更有光泽。唯一缺少的是闪亮动画。

上面的那个是我的控件,下面的是默认的WPF控件。

请记住,所有这些可能只需通过编辑进度条控件模板就能实现。

哦,多么闪亮...

以下是更新后的XAML代码:

<UserControl x:Class="WpfApplication1.MyProgressBar"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" x:Name="uc">
    <Grid>
        <Border Background="White" BorderBrush="Gray" BorderThickness="1">
            <Border BorderBrush="White" BorderThickness="1">
                <Grid>
                    <Grid.Background>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="#FFE5E5E5" Offset="0" />
                            <GradientStop Color="White" Offset="1" />
                        </LinearGradientBrush>
                    </Grid.Background>
                    <Grid Width="{Binding ProgressBarWidth, ElementName=uc, FallbackValue=200}" HorizontalAlignment="Left">
                        <Grid.Background>
                            <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
                                <GradientStop Color="#FF8BBA91" Offset="0" />
                                <GradientStop Color="#FF8BBA91" Offset="1" />
                                <GradientStop Color="#FF9ED76A" Offset="0.8" />
                                <GradientStop Color="#FF9ED76A" Offset="0.2" />
                            </LinearGradientBrush>
                        </Grid.Background>
                    </Grid>
                    <Border>
                        <Border.Background>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#89E2E2E2" Offset="0" />
                                <GradientStop Color="#C1FFFFFF" Offset="0.5" />
                                <GradientStop Color="Transparent" Offset="0.52" />
                            </LinearGradientBrush>
                        </Border.Background>
                    </Border>
                    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Percentage, ElementName=uc}"></TextBlock>
                </Grid>
            </Border>
        </Border>
    </Grid>
</UserControl>

谢谢Charleh!我会尝试使用Blend。是的,我需要一些花哨的东西,比如一个在中间显示百分比的.gif图像。我猜这应该可以用Blend实现! - now he who must not be named.
就像文森特所说的,您可以重新定义控件模板 - 如果您不需要通过绑定实现的其他功能,这可能会更好(我认为百分比指示器可以使用绑定来实现,我会尝试一下)。 - Charleh
是的,只需向项目添加一个新的UserControl,并复制/粘贴XAML。确保将XAML中的“x:Class”重命名为与您的新用户控件相同的命名空间/类。您还需要更改DependencyProperty.Register调用,以使typeof(MyProgressBar)使用您的uc类型名称。或者,您可以将整个部分复制/粘贴到新的UC中-它将重命名类为MyProgressBar,因此可能与文件名不匹配...然后您只需添加命名空间并添加控件。 - Charleh
你为什么不重新设计现有的控件,而是要创建一个新的控件? - Bob Vale
不,就像我说的,当控件模板更改时,旧的控件没有理由不能做到这一点。我只是想表明,如果需要一个自制控件,它比原始控件具有额外的功能(例如百分比文本 - 我也说过可能只需在原始控件模板上使用绑定即可实现),那么这是相当简单的。只是一点小乐趣 :) - Charleh
显示剩余3条评论

5
您需要在Windows的个性化设置中使用Aero主题(即Windows 7 Basic或Windows 7),才能获得平滑的进度条和动画发光效果。
Vista和Windows 7拥有Aero主题。当Windows XP发布时,它甚至不存在。在Windows 8中,为了更加统一的外观,它也被删除了。如果您切换到Windows Classic,则进度条会出现旧式的粗糙外观。
WPF有一组不同的模板,包括Luna、Aero、Royale、Classic等。它会查看您系统当前使用的主题,然后决定使用哪个WPF模板集。
因此,在XP上,它从未有机会使用Aero模板集。
如果出于某种原因,您希望即使Windows没有使用Aero主题,也要使进度条具有Aero外观,则有两种主要解决方案。
解决方案:
您可以强制您的WPF应用程序对其所有控件使用Aero主题的WPF模板:

如果您不想让所有应用程序控件都使用Aero主题,那么只需从Aero主题资源中获取定义ProgressBar的Aero外观的样式/模板,并将其应用于您的ProgressBar。

希望这两种方法都能让您获得发光的进度条...注意,我没有XP来测试是否有效。


1
您可以使用以下内容模仿动画效果,这是对已接受答案的微调:
<Grid Background="LightGray">
    <Grid Width="{Binding ProgressBarWidth, ElementName=uc}" HorizontalAlignment="Left">
        <Grid.Triggers>
            <EventTrigger RoutedEvent="Rectangle.Loaded">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetProperty="Background.(GradientBrush.GradientStops)[1].(GradientStop.Offset)" From="-1" To="0" Duration="0:0:1.5" RepeatBehavior="Forever"/>
                        <DoubleAnimation Storyboard.TargetProperty="Background.(GradientBrush.GradientStops)[2].(GradientStop.Offset)" From="0" To="1" Duration="0:0:1.5" RepeatBehavior="Forever"/>
                        <DoubleAnimation Storyboard.TargetProperty="Background.(GradientBrush.GradientStops)[3].(GradientStop.Offset)" From="1" To="2" Duration="0:0:1.5" RepeatBehavior="Forever"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Grid.Triggers>
        <Grid.Background>
            <LinearGradientBrush>
                <GradientStop Color="#FF218ED6" Offset="0.0" />
                <GradientStop Color="#FF4BA5E0" Offset="0.4" />
                <GradientStop Color="#FF8ECCF5" Offset="0.5" />
                <GradientStop Color="#FF4BA5E0" Offset="0.6" />
                <GradientStop Color="#FF218ED6" Offset="1.0" />
            </LinearGradientBrush>
        </Grid.Background>
    </Grid>
</Grid>

预览:

enter image description here


0
如果您想要改变进度条的外观,您需要重新定义它的(Control)Template。
微软在这里解释了这个问题:
http://msdn.microsoft.com/en-us/library/ms750638.aspx
在编写模板时,为了获得发光效果,您可以使用BitmapEffect和OuterGlowBitmapEffect(!软件渲染),但最好使用Effect(更加现代化)。
也许如果进度条的效果适合您,您不必重新定义模板。
请注意,您可以在网络上找到很多免费的应用程序主题。

谢谢Vincent!作为WPF的新手,这很有启发性。是的,我查看了Effect属性。(我点击了进度条,进入属性,搜索“Effect”)。它只显示“必须通过XAML设置值。如何在XAML中做到这一点?像<ProgressBar Effect="Glow"></ProgressBar>这样的东西。但是,这并没有起作用。那么,在XAML中我们应该指定什么样的Effect呢? - now he who must not be named.
Wpf有两种方式为属性赋值,使用第二种语法,在您的情况下是:<ProgressBar ....> <ProgressBar.Effect><BlurEffect Radius="2"/> </ProgressBar.Effect> </ProgressBar> - GameAlchemist
Vincent Piel,你的代码让进度条看起来相当不错。谢谢你。但是还是没有发光效果!? - now he who must not be named.
也许尝试使用已弃用的OuterGlowBitmapEffect...我不知道,我从来没有做过发光效果。在网络上搜索有关如何制作发光效果的特定点。 - GameAlchemist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接