Dispatcher中Invoke与BeginInvoke

[同步]Invoke

Application.Current.Dispatcher.Invoke(AutoIncreaseNumber);

[异步]BeginInvoke

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

两者都会阻塞UI线程

基于WPF4.5.1示例

Dispatcher中Invoke与BeginInvoke

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

结果如下:

Dispatcher中Invoke与BeginInvoke

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

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

 

代码

 

你可能感兴趣的:(dispatcher)