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

    代码

  • 相关阅读:
    IIS: 必须输入密码手动设置密码同步后
    IIS操作控制类
    SQL对IP地址进行拆分
    HTTP_REFERER的工作方式[转贴]
    如何知道同服务器上都有哪些网站?
    简单判断临时表是否存在
    .NET 3.5 SP 1发布了
    Log Parser很好很强大的IIS日志分析工具
    遍历Request.ServerVariables
    06复杂查询(多数据库表)
  • 原文地址:https://www.cnblogs.com/XzcBlog/p/4428910.html
Copyright © 2011-2022 走看看