• 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是没有等待执行完就接着往下走了,然后会根据线程的调用优先级开始执行。

    代码

  • 相关阅读:
    King's Quest
    JavaScript“并非”一切皆对象
    javascript中的style只能取到在HTML中定义的css属性
    jquery中的$(this)和this
    WEB安全字体(Web Safe Fonts)-网页设计用什么字体兼容性好?
    css各种水平垂直居中
    css绘制各种形状
    css3椭圆运动
    通过时间戳控制类
    js中的面向对象程序设计
  • 原文地址:https://www.cnblogs.com/XzcBlog/p/4428910.html
Copyright © 2020-2023  润新知