• WPF Loading


    背景:WPF项目中,经常会处理一个或者多个耗时很久的任务,比如调用服务的数据查询然后把N条数据加载到列表控件。这种情况下如果采用一般的方式同步处理那么WPF的UI就会失去响应,卡死在那个地方,整个系统可能都无法操作,这对用户来说简直就是太不友好了,也得傻傻的等待任务完成才能干其他事件......

    这个问题的解决方法都是采用多线程来处理,一般是开起一个后台线程去完成这些任务,这样UI线程仍然可以响应用户的其它操作,等待后台把任务处理完毕了在通知UI、通知用户。这样不仅提高了效率、也让系统的体验更好。

    WPF的WPFToolKit、WPFToolKitExtended里面给我提供了一个BusyIndicator的控件(具体用法这里不讲了,有兴趣的朋友自己去查吧)。使用它可以很好的提示用户系统正在处理的任务和进度等。。。但是它的样式外观个人觉得不大好,还是比较喜欢那种转圈的。于是自己模仿它重新写了一个控件,用法和BusyIndicator一样,在这里分享一下,希望对大家有用。下面是效果图:

     

    下面贴出控件后台代码及其实现动画的代码仅供参考: 

    后台代码及动画实现
      1  using System;
      2  using System.Windows;
      3  using System.Windows.Controls;
      4  using System.Windows.Shapes;
      5  using System.Windows.Threading;
      6  using System.Windows.Media;
      7  using System.Windows.Media.Animation;
      8  
      9  namespace BusyIndicator
     10  {
     11      /// <summary>
     12      /// A control to provide a visual indicator when an application is busy.
     13      /// </summary>
     14      [TemplateVisualState(Name = VisualStates.StateIdle, GroupName = VisualStates.GroupBusyStatus)]
     15      [TemplateVisualState(Name = VisualStates.StateBusy, GroupName = VisualStates.GroupBusyStatus)]
     16      [TemplateVisualState(Name = VisualStates.StateVisible, GroupName = VisualStates.GroupVisibility)]
     17      [TemplateVisualState(Name = VisualStates.StateHidden, GroupName = VisualStates.GroupVisibility)]
     18      [StyleTypedProperty(Property = "OverlayStyle", StyleTargetType = typeof(Rectangle))]
     19      [StyleTypedProperty(Property = "ProgressBarStyle", StyleTargetType = typeof(ProgressBar))]
     20      public class BusyIndicator : ContentControl
     21      {
     22          /// <summary>
     23          /// Gets or sets a value indicating whether the BusyContent is visible.
     24          /// </summary>
     25          protected bool IsContentVisible { get; set; }
     26  
     27          /// <summary>
     28          /// Timer used to delay the initial display and avoid flickering.
     29          /// </summary>
     30          private DispatcherTimer _displayAfterTimer;
     31  
     32          /// <summary>
     33          /// Instantiates a new instance of the BusyIndicator control.
     34          /// </summary>
     35          public BusyIndicator()
     36          {
     37              DefaultStyleKey = typeof(BusyIndicator);
     38              _displayAfterTimer = new DispatcherTimer();
     39              _displayAfterTimer.Tick += new EventHandler(DisplayAfterTimerElapsed);
     40              this.BusyContent = InitBusyContent();
     41          }
     42  
     43          /// <summary>
     44          /// Overrides the OnApplyTemplate method.
     45          /// </summary>
     46          public override void OnApplyTemplate()
     47          {
     48              base.OnApplyTemplate();
     49              ChangeVisualState(false);
     50          }
     51  
     52          /// <summary>
     53          /// Handler for the DisplayAfterTimer.
     54          /// </summary>
     55          /// <param name="sender">Event sender.</param>
     56          /// <param name="e">Event arguments.</param>
     57          private void DisplayAfterTimerElapsed(object sender, EventArgs e)
     58          {
     59              _displayAfterTimer.Stop();
     60              IsContentVisible = true;
     61              ChangeVisualState(true);
     62          }
     63  
     64          /// <summary>
     65          /// Changes the control's visual state(s).
     66          /// </summary>
     67          /// <param name="useTransitions">True if state transitions should be used.</param>
     68          protected virtual void ChangeVisualState(bool useTransitions)
     69          {
     70              VisualStateManager.GoToState(this, IsBusy ? VisualStates.StateBusy : VisualStates.StateIdle, useTransitions);
     71              VisualStateManager.GoToState(this, IsContentVisible ? VisualStates.StateVisible : VisualStates.StateHidden, useTransitions);
     72          }
     73  
     74          /// <summary>
     75          /// Gets or sets a value indicating whether the busy indicator should show.
     76          /// </summary>
     77          public bool IsBusy
     78          {
     79              get { return (bool)GetValue(IsBusyProperty); }
     80              set { SetValue(IsBusyProperty, value); }
     81          }
     82  
     83          /// <summary>
     84          /// Identifies the IsBusy dependency property.
     85          /// </summary>
     86          public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register(
     87              "IsBusy",
     88              typeof(bool),
     89              typeof(BusyIndicator),
     90              new PropertyMetadata(false, new PropertyChangedCallback(OnIsBusyChanged)));
     91  
     92          /// <summary>
     93          /// IsBusyProperty property changed handler.
     94          /// </summary>
     95          /// <param name="d">BusyIndicator that changed its IsBusy.</param>
     96          /// <param name="e">Event arguments.</param>
     97          private static void OnIsBusyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
     98          {
     99              ((BusyIndicator)d).OnIsBusyChanged(e);
    100          }
    101  
    102          /// <summary>
    103          /// IsBusyProperty property changed handler.
    104          /// </summary>
    105          /// <param name="e">Event arguments.</param>
    106          protected virtual void OnIsBusyChanged(DependencyPropertyChangedEventArgs e)
    107          {
    108              if (IsBusy)
    109              {
    110                  if (DisplayAfter.Equals(TimeSpan.Zero))
    111                  {
    112                      // Go visible now
    113                      IsContentVisible = true;
    114                  }
    115                  else
    116                  {
    117                      // Set a timer to go visible
    118                      _displayAfterTimer.Interval = DisplayAfter;
    119                      _displayAfterTimer.Start();
    120                  }
    121              }
    122              else
    123              {
    124                  // No longer visible
    125                  _displayAfterTimer.Stop();
    126                  IsContentVisible = false;
    127              }
    128              ChangeVisualState(true);
    129          }
    130  
    131          /// <summary>
    132          /// Gets or sets a value indicating the busy content to display to the user.
    133          /// </summary>
    134          public object BusyContent
    135          {
    136              get { return (object)GetValue(BusyContentProperty); }
    137              set { SetValue(BusyContentProperty, value); }
    138          }
    139  
    140          /// <summary>
    141          /// Identifies the BusyContent dependency property.
    142          /// </summary>
    143          public static readonly DependencyProperty BusyContentProperty = DependencyProperty.Register(
    144              "BusyContent",
    145              typeof(object),
    146              typeof(BusyIndicator),
    147              new PropertyMetadata(null));
    148  
    149          /// <summary>
    150          /// Gets or sets a value indicating the template to use for displaying the busy content to the user.
    151          /// </summary>
    152          public DataTemplate BusyContentTemplate
    153          {
    154              get { return (DataTemplate)GetValue(BusyContentTemplateProperty); }
    155              set { SetValue(BusyContentTemplateProperty, value); }
    156          }
    157  
    158          /// <summary>
    159          /// Identifies the BusyTemplate dependency property.
    160          /// </summary>
    161          public static readonly DependencyProperty BusyContentTemplateProperty = DependencyProperty.Register(
    162              "BusyContentTemplate",
    163              typeof(DataTemplate),
    164              typeof(BusyIndicator),
    165              new PropertyMetadata(null));
    166  
    167          /// <summary>
    168          /// Gets or sets a value indicating how long to delay before displaying the busy content.
    169          /// </summary>
    170          public TimeSpan DisplayAfter
    171          {
    172              get { return (TimeSpan)GetValue(DisplayAfterProperty); }
    173              set { SetValue(DisplayAfterProperty, value); }
    174          }
    175  
    176          /// <summary>
    177          /// Identifies the DisplayAfter dependency property.
    178          /// </summary>
    179          public static readonly DependencyProperty DisplayAfterProperty = DependencyProperty.Register(
    180              "DisplayAfter",
    181              typeof(TimeSpan),
    182              typeof(BusyIndicator),
    183              new PropertyMetadata(TimeSpan.FromSeconds(0.1)));
    184  
    185          /// <summary>
    186          /// Gets or sets a value indicating the style to use for the overlay.
    187          /// </summary>
    188          public Style OverlayStyle
    189          {
    190              get { return (Style)GetValue(OverlayStyleProperty); }
    191              set { SetValue(OverlayStyleProperty, value); }
    192          }
    193  
    194          /// <summary>
    195          /// Identifies the OverlayStyle dependency property.
    196          /// </summary>
    197          public static readonly DependencyProperty OverlayStyleProperty = DependencyProperty.Register(
    198              "OverlayStyle",
    199              typeof(Style),
    200              typeof(BusyIndicator),
    201              new PropertyMetadata(null));
    202  
    203          /// <summary>
    204          /// Gets or sets a value indicating the style to use for the progress bar.
    205          /// </summary>
    206          public Style ProgressBarStyle
    207          {
    208              get { return (Style)GetValue(ProgressBarStyleProperty); }
    209              set { SetValue(ProgressBarStyleProperty, value); }
    210          }
    211  
    212          /// <summary>
    213          /// Identifies the ProgressBarStyle dependency property.
    214          /// </summary>
    215          public static readonly DependencyProperty ProgressBarStyleProperty = DependencyProperty.Register(
    216              "ProgressBarStyle",
    217              typeof(Style),
    218              typeof(BusyIndicator),
    219              new PropertyMetadata(null));
    220  
    221          #region BusyContent
    222  
    223          private Grid InitBusyContent()
    224          {
    225              var g = new Grid();  
    226              #region AddPaths
    227              int counter = 12;
    228              for (int i = 0; i < counter; i++)
    229              {
    230                  Path path = new Path();
    231                  path.Data = Geometry.Parse("M 0,0 L -1,0 L -1,-12 L 0,-13 L 1,-12 L 1,0 Z");
    232                  path.Stroke = new SolidColorBrush(Colors.SkyBlue);
    233                  path.Fill = new SolidColorBrush(Colors.SkyBlue);
    234                  path.Opacity = 0.1;
    235  
    236                  TransformGroup tg = new TransformGroup();
    237                  path.RenderTransform = tg;
    238                  TranslateTransform tt = new TranslateTransform();
    239                  tt.Y = -8; tt.X = 1;
    240  
    241                  RotateTransform rt = new RotateTransform();
    242                  rt.Angle = i * 30;
    243                  tg.Children.Add(tt);
    244                  tg.Children.Add(rt);  
    245  
    246                  DoubleAnimation da = new DoubleAnimation();
    247                  da.From = 1.0;
    248                  da.To = 0.1;
    249                  da.Duration = new Duration(TimeSpan.FromSeconds(1));
    250  
    251                  da.BeginTime = TimeSpan.FromMilliseconds(i * 1000 / counter);
    252                  da.RepeatBehavior = RepeatBehavior.Forever;
    253  
    254                  path.VerticalAlignment = System.Windows.VerticalAlignment.Center;
    255                  path.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
    256                  g.Children.Add(path); 
    257                  path.BeginAnimation(Path.OpacityProperty, da);
    258              }
    259              return g;
    260  
    261              #endregion
    262          }
    263  
    264          #endregion
    265      }
    266  }

     下面是实现的整个工程代码:

    /Files/rpoplar/BusyIndicator.zip 

  • 相关阅读:
    HTML5服务器发送事件(Server-Send Events)
    无人问津的排序(一)----希尔排序
    NB二人组(二)----归并排序
    40、常用字符串格式化有哪几种?
    39、请用代码简答实现stack
    38、一行代码实现删除列表中重复的值 ?
    37、如何在函数中设置一个全局变量 ?
    NB二人组(一)----堆排序
    快排
    LOW逼三人组(三)----插入排序
  • 原文地址:https://www.cnblogs.com/rpoplar/p/BusyIndicator.html
Copyright © 2020-2023  润新知