zoukankan      html  css  js  c++  java
  • 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 

  • 相关阅读:
    优化SQL查询:如何写出高性能SQL语句
    提高SQL执行效率的16种方法
    Spring Ioc DI 原理
    java内存泄漏
    转:js闭包
    LeetCode Best Time to Buy and Sell Stock III
    LeetCode Best Time to Buy and Sell Stock with Cooldown
    LeetCode Length of Longest Fibonacci Subsequence
    LeetCode Divisor Game
    LeetCode Sum of Even Numbers After Queries
  • 原文地址:https://www.cnblogs.com/rpoplar/p/BusyIndicator.html
Copyright © 2011-2022 走看看