Progress bar style in WPF is old fashioned. Increm

2019-03-30 06:54发布

问题:

Progress bar style in WPF is old fashioned. Increments in Bars. How to implement a progress bar with vista or windows-7 shady glow effect ?

Image http://quickshare.my3gb.com/download/2.JPG

Even checked out the properties of the Progressbar. But, there is no properties related to glowy effect.

Also, is there any animations or something different from normal progress bar/

Thanks in Adv.

Edit The Code

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

</ProgressBar>

回答1:

Roll your own shouldn't be too hard.

Create a usercontrol which has the properties of a standard progress bar

Value
Maximum
Minimum

You can create a derived property which calculates the size of the bar by using the a formula:

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

Which changes when the Value, Maximum or Minimum is updated

Bind this to the Width of the 'bar' in your progress bar control template - this way when the Value property is updated, the progress bar will resize.

How your bar looks is up to you, but I guess you just want a load of fancy fills/gradients/glow effects - you can add these in Blend

Disclaimer: Formulas may be incorrect!

In case you want to try and roll your own, here's one I just knocked up which seems to work ok

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


        }          
    }

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

The result:

Like I said, something like this is pretty easy but still consider redefining the template or using the original since it does support glowyness on the right OS

Here it is after I added a 'Percent' dependency property and bound to that in the control template:

Code for updating Percent was

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

Edit 2:

I messed with the fills and added a white inner border so it looks more shiny. The only thing missing is the shiny animation

the top one is my control, the bottom one is the default WPF one

Bear in mind, all of this may be possible just by editing the progress bar control template

Here's the updated 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>


回答2:

You need to be using the Aero theme (i.e. Windows 7 Basic, or Windows 7) in your Personalization settings of Windows in order to get the smooth progress bar and animated glow look.

Vista and Windows 7 have the Aero theme. It didn't even exist when Windows XP was released. It was also removed in Windows 8 for a more standard look across the board. If you switch to Windows Classic then you get the old chunky bars look for the progress bar.

WPF has a different set of Templates defined for Luna, Aero, Royale, Classic.....what it does is look at the theme your system is currently using, and then this makes it decide which set of WPF Templates to use.

So when you are on XP, it never gets the opportunity to use the Aero set of templates.

If for some reason you want to have your progress bar themed with the Aero look even when Windows is not using the Aero theme then there are 2 main solutions.

The solutions:

You can force your WPF application to use the Aero-themed WPF templates for all of its controls:

  • http://arbel.net/2006/11/03/forcing-wpf-to-use-a-specific-windows-theme/

  • http://www.kennethham.com/wp/2010/11/force-wpf-to-use-windows-7aero-theming-in-classic-mode/

OR

If you don't want all of your applications controls to be themed as Aero, then just take the style/template that defines the Aero look of the ProgressBar from the Aero theme resources and apply it to your ProgressBar.

  • Where can I download Microsoft's standard WPF themes from?

Hopefully either way will get you your glowing progress bar....note, I don't have XP to test if this is the case.



回答3:

If you want to change the look of the Progress Bar, you'll have to re-define its (Control)Template.
ms explains this here :
http://msdn.microsoft.com/en-us/library/ms750638.aspx
When writing the Template, to get the glow, You can use the BitmapEffect, with a OuterGlowBitmapEffect (!Software rendered), but Best is to use Effect (more up to date).

Maybe you don't have to redefine the Template if you use the Effect of the progress bar and it suits you.

Notice that you have good free themes for your application on the net.



回答4:

You can mimic the animation using the following, which is a tweak for the accepted answer:

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

Preview: