zoukankan      html  css  js  c++  java
  • Dispatcher中Invoke与BeginInvoke

    [同步]Invoke

    Application.Current.Dispatcher.Invoke(AutoIncreaseNumber);

    [异步]BeginInvoke

    Application.Current.Dispatcher.BeginInvoke((Action)AutoIncreaseNumber);

    两者都会阻塞UI线程

    基于WPF4.5.1示例

    Invoke 按钮对应的是InvokeCommand

    BeginInvoke按钮对应的是BeginInvokeCommand

    可以发现,在执行按钮的命令时,UI线程是会阻塞,计时器并不会走动

      1 public class MainViewModel : ViewModelBase
      2     {
      3         public MainViewModel()
      4         {
      5             DispatcherTimer timer = new DispatcherTimer();
      6             timer.Interval = TimeSpan.FromSeconds(1);
      7             timer.Tick += timer_Tick;
      8             timer.Start();
      9         }
     10 
     11         void timer_Tick(object sender, EventArgs e)
     12         {
     13             Now = DateTime.Now;
     14         }
     15 
     16         private DateTime now = DateTime.Now;
     17 
     18         public DateTime Now
     19         {
     20             get { return now; }
     21             set
     22             {
     23                 now = value;
     24                 RaisePropertyChanged("Now");
     25             }
     26         }
     27 
     28 
     29 
     30         private int number;
     31         /// <summary>
     32         /// 数值用于显示
     33         /// </summary>
     34         public int Number
     35         {
     36             get { return number; }
     37             set
     38             {
     39                 number = value;
     40                 RaisePropertyChanged("Number");
     41             }
     42         }
     43 
     44         private bool isIncrease;
     45         /// <summary>
     46         /// 是否可以自增长
     47         /// </summary>
     48         public bool IsIncrease
     49         {
     50             get { return isIncrease; }
     51             set
     52             {
     53                 isIncrease = value;
     54                 RaisePropertyChanged("IsIncrease");
     55             }
     56         }
     57 
     58         /// <summary>
     59         /// 自动增长
     60         /// </summary>
     61         private void AutoIncreaseNumber()
     62         {
     63             IsIncrease = !isIncrease;
     64             while (IsIncrease && Number < 500000)
     65             {
     66                 Number++;
     67             }
     68         }
     69 
     70         #region RelayCommands
     71         /// <summary>
     72         /// Invoke命令 
     73         /// </summary>
     74         public RelayCommand InvokeCommand
     75         {
     76             get
     77             {
     78                 return new RelayCommand(() =>
     79                 {
     80                     Application.Current.Dispatcher.Invoke(AutoIncreaseNumber);
     81                 });
     82             }
     83         }
     84         /// <summary>
     85         /// BeginInvoke命令
     86         /// </summary>
     87         public RelayCommand BeginInvokeCommand
     88         {
     89             get
     90             {
     91                 return new RelayCommand(() =>
     92                 {
     93                     //这里直接使用匿名方法会报错
     94                     //'Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type'
     95                     //使用强制转换的方式
     96                     Application.Current.Dispatcher.BeginInvoke((Action)AutoIncreaseNumber);
     97                 });
     98             }
     99         }
    100         /// <summary>
    101         /// 清理数字命令
    102         /// </summary>
    103         public RelayCommand ClearCommand
    104         {
    105             get
    106             {
    107                 return new RelayCommand(() =>
    108                     {
    109                         Number = 0;
    110                         IsIncrease = false;
    111                     });
    112             }
    113         }
    114         #endregion
    115     }
    View Code

    注:其中阻塞UI线程的原因是把Number的递增放到了Dispather中去执行,如果想要不阻塞,那么需要有一个新的DispatcherTimer的对象去执行这个递增的逻辑,那么就不会阻塞UI线程了。

    所以说这里所说的异步并不是相对于UI线程的异步,那么究竟是什么?

    Invoke 是同步操作;因此,直到回调返回之后才会将控制权返回给调用对象。

    BeginInvoke 是异步操作;因此,调用之后控制权会立即返回给调用对象。

                                   --- msdn

    做一个测试

     1 /// <summary>
     2     /// DiffInInvokeAndBeginInvoke.xaml 的交互逻辑
     3     /// </summary>
     4     public partial class DiffInInvokeAndBeginInvoke : Window
     5     {
     6         public DiffInInvokeAndBeginInvoke()
     7         {
     8             InitializeComponent();
     9             this.ltb.ItemsSource = _infos;
    10             this.Loaded += DiffInInvokeAndBeginInvoke_Loaded;
    11         }
    12 
    13         private ObservableCollection<string> _infos = new ObservableCollection<string>();
    14 
    15         private void DiffInInvokeAndBeginInvoke_Loaded(object sender, RoutedEventArgs e)
    16         {
    17             ExcuteMethod();
    18             ExcuteMethod_2();
    19             ExcuteMethod_3();
    20         }
    21 
    22         private void ExcuteMethod()
    23         {
    24             Dispatcher.Invoke(new Action<string>(PrintInformation), System.Windows.Threading.DispatcherPriority.SystemIdle, "1-1: SystemIdle Invoke");
    25             Dispatcher.Invoke(new Action<string>(PrintInformation), System.Windows.Threading.DispatcherPriority.Send, "1-2: Send Invoke ");
    26             Dispatcher.BeginInvoke(new Action<string>(PrintInformation), System.Windows.Threading.DispatcherPriority.Normal, "1-3: Normal BeginInvoke");
    27             Dispatcher.BeginInvoke(new Action<string>(PrintInformation), System.Windows.Threading.DispatcherPriority.Send, "1-4: Send BeginInvoke");
    28             DispatcherOperation dop = Dispatcher.BeginInvoke(new Action<string>(PrintInformation), "1-5: Defaut BeginInvoke");
    29         }
    30 
    31         private void ExcuteMethod_2()
    32         {
    33 
    34             Dispatcher.BeginInvoke(new Action<string>(PrintInformation), System.Windows.Threading.DispatcherPriority.Normal, "2-1: Normal BeginInvoke");
    35             Dispatcher.Invoke(new Action<string>(PrintInformation), System.Windows.Threading.DispatcherPriority.Send, "2-2: Send Invoke ");
    36             Dispatcher.BeginInvoke(new Action<string>(PrintInformation), System.Windows.Threading.DispatcherPriority.Send, "2-3: Send BeginInvoke");
    37         }
    38 
    39         private void ExcuteMethod_3()
    40         {
    41             Dispatcher.Invoke(new Action<string>(PrintInformation), System.Windows.Threading.DispatcherPriority.Send, "3-1: Send Invoke ");
    42             Dispatcher.BeginInvoke(new Action<string>(PrintInformation), System.Windows.Threading.DispatcherPriority.Send, "2-2: Send BeginInvoke");
    43         }
    44 
    45         private void PrintInformation(string info)
    46         {
    47             _infos.Add(info);
    48         }
    49     }
    View Code

    结果如下:

    从结果及MSDN对于Invoke及BeginInvoke的解释,很容易就理解了。

    Invoke一定要执行完了才会执行下去,而BeginInvoke是没有等待执行完就接着往下走了,然后会根据线程的调用优先级开始执行。

    代码

  • 相关阅读:
    HDU4474 Yet Another Multiple Problem BFS搜索
    HDU4473 Exam 数学分析
    2013ACM多校联合(4)
    POJ1273 网络流...
    HDU4472 Count 递推
    POJ1149 PIGS 网络流
    UVA10881 Piotr's Ants 想法题
    javascript js string.Format()收集
    修改 设置 vs.net 网站 调试 设为 起始页
    【转】HTML5杂谈 概念与现行游戏 割绳子 宝石迷阵
  • 原文地址:https://www.cnblogs.com/XzcBlog/p/4428910.html
Copyright © 2011-2022 走看看