Dispatcher中Invoke与BeginInvoke-阿里云开发者社区

开发者社区> 杰克.陈> 正文

Dispatcher中Invoke与BeginInvoke

简介: 原文:Dispatcher中Invoke与BeginInvoke [同步]Invoke Application.Current.Dispatcher.Invoke(AutoIncreaseNumber); [异步]BeginInvoke Application.
+关注继续查看
原文: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是没有等待执行完就接着往下走了,然后会根据线程的调用优先级开始执行。

 

代码

 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
9485 0
使用NAT网关轻松为单台云服务器设置多个公网IP
在应用中,有时会遇到用户询问如何使单台云服务器具备多个公网IP的问题。 具体如何操作呢,有了NAT网关这个也不是难题。
26734 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
11191 0
windows server 2008阿里云ECS服务器安全设置
最近我们Sinesafe安全公司在为客户使用阿里云ecs服务器做安全的过程中,发现服务器基础安全性都没有做。为了为站长们提供更加有效的安全基础解决方案,我们Sinesafe将对阿里云服务器win2008 系统进行基础安全部署实战过程! 比较重要的几部分 1.
9049 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13168 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
4008 0
阿里云ECS云服务器初始化设置教程方法
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
6886 0
+关注
杰克.陈
一个安静的程序猿~
10427
文章
2
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载