WPF 进度条ProgressBar

今天研究了一下wpf的进度条ProgressBar

1.传统ProgressBar

WPF进度条ProgressBar 这个控件,如果直接写到循环里,会死掉,界面会卡死,不会有进度。需要把进度条放到单独的线程中。

传统的需要建立 Thread 或者使用 Timer,分别写在不同的方法中。但现在,使用 Dispatcher.Invoke 调用可以实现这个目的。

for (int i = 0; i <= 10000; i++)
            {
                double value = i * 100.0 / 10000;
                lbShow.Content = "总大小:" + 10000 + ",已导入:" + i;
                pbBar.Dispatcher.Invoke(new Action<System.Windows.DependencyProperty, object>(pbBar.SetValue), System.Windows.Threading.DispatcherPriority.Background, ProgressBar.ValueProperty, value);
            }

pbBar是ProgressBar的名称。下图是传统进度条显示的效果。

传统的进度条看着比价简单,没有高大上的感觉。所以一般很少受到广大人民的喜好。

2.圆形进度条(这是借鉴了网上一位网友的,如侵犯到版权,请给我留言)

圆形进度条,如下图,同样是用ProgressBar控件,但感觉就会不一样

要显示这个效果,首先要编写一个类,这里编写的类是ValueToProcessConverter.cs类,源码是

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;

namespace WpfSqlHelp
{
    class ValueToProcessConverter : IValueConverter
    {
        private const double Thickness = 8;
        private const double Padding = 1;
        private const double WarnValue = 60;
        private const int SuccessRateFontSize = 34;
        private static readonly SolidColorBrush NormalBrush;
        private static readonly SolidColorBrush WarnBrush;
        private static readonly Typeface SuccessRateTypeface;

        private string percentString;
        private Point centerPoint;
        private double radius;

        static ValueToProcessConverter()
        {
            NormalBrush = new SolidColorBrush(Colors.Green);
            WarnBrush = new SolidColorBrush(Colors.Red);
            SuccessRateTypeface = new Typeface(new FontFamily("MSYH"), new FontStyle(), new FontWeight(), new FontStretch());
        }

        public ValueToProcessConverter()
        {

        }

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is double && !string.IsNullOrEmpty((string)parameter)) {
                double arg = (double)value;
                double width = double.Parse((string)parameter);
                radius = width / 2;
                centerPoint = new Point(radius, radius);

                return DrawBrush(arg, 100, radius, radius, Thickness, Padding);
            } else {
                throw new ArgumentException();
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 根据角度获取坐标
        /// </summary>
        /// <param name="CenterPoint"></param>
        /// <param name="r"></param>
        /// <param name="angel"></param>
        /// <returns></returns>
        private Point GetPointByAngel(Point CenterPoint, double r, double angel)
        {
            Point p = new Point();
            p.X = Math.Sin(angel * Math.PI / 180) * r + CenterPoint.X;
            p.Y = CenterPoint.Y - Math.Cos(angel * Math.PI / 180) * r;

            return p;
        }

        /// <summary>
        /// 根据4个坐标画出扇形
        /// </summary>
        /// <param name="bigFirstPoint"></param>
        /// <param name="bigSecondPoint"></param>
        /// <param name="smallFirstPoint"></param>
        /// <param name="smallSecondPoint"></param>
        /// <param name="bigRadius"></param>
        /// <param name="smallRadius"></param>
        /// <param name="isLargeArc"></param>
        /// <returns></returns>
        private Geometry DrawingArcGeometry(Point bigFirstPoint, Point bigSecondPoint, Point smallFirstPoint, Point smallSecondPoint, double bigRadius, double smallRadius, bool isLargeArc)
        {
            PathFigure pathFigure = new PathFigure { IsClosed = true };
            pathFigure.StartPoint = bigFirstPoint;
            pathFigure.Segments.Add(
              new ArcSegment {
                  Point = bigSecondPoint,
                  IsLargeArc = isLargeArc,
                  Size = new Size(bigRadius, bigRadius),
                  SweepDirection = SweepDirection.Clockwise
              });
            pathFigure.Segments.Add(new LineSegment { Point = smallSecondPoint });
            pathFigure.Segments.Add(
             new ArcSegment {
                 Point = smallFirstPoint,
                 IsLargeArc = isLargeArc,
                 Size = new Size(smallRadius, smallRadius),
                 SweepDirection = SweepDirection.Counterclockwise
             });
            PathGeometry pathGeometry = new PathGeometry();
            pathGeometry.Figures.Add(pathFigure);

            return pathGeometry;
        }

        /// <summary>
        /// 根据当前值和最大值获取扇形
        /// </summary>
        /// <param name="value"></param>
        /// <param name="maxValue"></param>
        /// <returns></returns>
        private Geometry GetGeometry(double value, double maxValue, double radiusX, double radiusY, double thickness, double padding)
        {
            bool isLargeArc = false;
            double percent = value / maxValue;
            percentString = string.Format("{0}%", Math.Round(percent * 100));
            double angel = percent * 360D;
            if (angel > 180) isLargeArc = true;
            double bigR = radiusX;
            double smallR = radiusX - thickness + padding;
            Point firstpoint = GetPointByAngel(centerPoint, bigR, 0);
            Point secondpoint = GetPointByAngel(centerPoint, bigR, angel);
            Point thirdpoint = GetPointByAngel(centerPoint, smallR, 0);
            Point fourpoint = GetPointByAngel(centerPoint, smallR, angel);
            return DrawingArcGeometry(firstpoint, secondpoint, thirdpoint, fourpoint, bigR, smallR, isLargeArc);
        }

        private void DrawingGeometry(DrawingContext drawingContext, double value, double maxValue, double radiusX, double radiusY, double thickness, double padding)
        {
            if (value != maxValue) {
                SolidColorBrush brush;
                if (value < WarnValue) {
                    brush = WarnBrush;
                } else {
                    brush = NormalBrush;
                }
                drawingContext.DrawEllipse(null, new Pen(new SolidColorBrush(Color.FromRgb(0xdd, 0xdf, 0xe1)), thickness), centerPoint, radiusX, radiusY);
                drawingContext.DrawGeometry(brush, new Pen(), GetGeometry(value, maxValue, radiusX, radiusY, thickness, padding));
                FormattedText formatWords = new FormattedText(percentString,
                    CultureInfo.CurrentCulture,
                    FlowDirection.LeftToRight,
                    SuccessRateTypeface,
                    SuccessRateFontSize,
                    brush);
                Point startPoint = new Point(centerPoint.X - formatWords.Width / 2, centerPoint.Y - formatWords.Height / 2);
                drawingContext.DrawText(formatWords, startPoint);
            } else {
                drawingContext.DrawEllipse(null, new Pen(NormalBrush, thickness), centerPoint, radiusX, radiusY);
                FormattedText formatWords = new FormattedText("100%",
                    CultureInfo.CurrentCulture,
                    FlowDirection.LeftToRight,
                    SuccessRateTypeface,
                    SuccessRateFontSize,
                    NormalBrush);
                Point startPoint = new Point(centerPoint.X - formatWords.Width / 2, centerPoint.Y - formatWords.Height / 2);
                drawingContext.DrawText(formatWords, startPoint);
            }

            drawingContext.Close();
        }

        /// <summary>
        /// 根据当前值和最大值画出进度条
        /// </summary>
        /// <param name="value"></param>
        /// <param name="maxValue"></param>
        /// <returns></returns>
        private Visual DrawShape(double value, double maxValue, double radiusX, double radiusY, double thickness, double padding)
        {
            DrawingVisual drawingWordsVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingWordsVisual.RenderOpen();

            DrawingGeometry(drawingContext, value, maxValue, radiusX, radiusY, thickness, padding);

            return drawingWordsVisual;
        }

        /// <summary>
        /// 根据当前值和最大值画出进度条
        /// </summary>
        /// <param name="value"></param>
        /// <param name="maxValue"></param>
        /// <returns></returns>
        private Brush DrawBrush(double value, double maxValue, double radiusX, double radiusY, double thickness, double padding)
        {
            DrawingGroup drawingGroup = new DrawingGroup();
            DrawingContext drawingContext = drawingGroup.Open();

            DrawingGeometry(drawingContext, value, maxValue, radiusX, radiusY, thickness, padding);

            DrawingBrush brush = new DrawingBrush(drawingGroup);

            return brush;
        }

    }
}
ValueToProcessConverter.cs源码

其次要在相应wpf窗体上做相应修改

(1)在窗体上的xaml代码为

<Window x:Class="WpfSqlHelp.TelNumWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfSqlHelp"
        Title="TelNumWindow" Height="300" Width="300">
    <Window.Resources>
        <local:ValueToProcessConverter x:Key="ValueToProcessConverter"/>
    </Window.Resources>
    <Grid>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="30"></RowDefinition>
                <RowDefinition Height="30"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Button Name="btnInput"  Content="数据导入" HorizontalAlignment="Left" Margin="77,5,0,0" VerticalAlignment="Top" Width="75" Click="btnInput_Click"/>           
            <Label Name="lbShow" Grid.Row="1"  HorizontalAlignment="Left" Margin="38,5,0,0" VerticalAlignment="Top"  RenderTransformOrigin="-0.375,0.3"/>
            <ProgressBar Name="pbBar" Grid.Row="2"  Minimum="0"
                     Maximum="100"
                     Value="{Binding SuccessRate, Mode=OneWay}">
                <ProgressBar.Template>
                    <ControlTemplate TargetType="ProgressBar">
                        <Border Background="{TemplateBinding Value, Converter={StaticResource ValueToProcessConverter}, ConverterParameter=200}"/>
                    </ControlTemplate>
                </ProgressBar.Template>
            </ProgressBar>
        </Grid>        
    </Grid>
</Window>
红色标注的是需要注意修改的地方。

(2)在代码中的编写为

namespace WpfSqlHelp
{
    /// <summary>
    /// TelNumWindow.xaml 的交互逻辑
    /// </summary>
    public partial class TelNumWindow : Window, INotifyPropertyChanged
    {
        public TelNumWindow()
        {
            InitializeComponent();
        }

        private void btnInput_Click(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i <= 10000; i++)
            {
                double value = i * 100.0 / 10000;
                lbShow.Content = "总大小:" + 10000 + ",已导入:" + i;
                pbBar.Dispatcher.Invoke(new Action<System.Windows.DependencyProperty, object>(pbBar.SetValue), System.Windows.Threading.DispatcherPriority.Background, ProgressBar.ValueProperty, value);
            }
        }

        #region INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

    }
}
如果这些都搞好,运行你就会看到圆形进度条。

 

posted @ 2016-04-12 13:43  幻影星辰  阅读(17269)  评论(0编辑  收藏  举报