转载

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

时间:2015年04月15日 | 作者 : aaronyang | 分类 :WPF4.5系列 | 浏览: 10次 | 评论0人

文章摘要:

1. 通过简单DEMO.让读者理解Task和Task<T>    学习过程中,掌握async和await  

2. 理解同步和异步的执行  

3. Task.Factory.StartNew()的替代  

4. WPF中传统方式async的应用,让界面不卡  

5. Ay 自编的无任何组件的 快速的MVVM应用,Async版本,实战DEMO  

以下DEMO 以vs2013开发 .Net Framework4.5+  控制台程序为主

前言: async标记    await异步执行方法,可返回值可不返回,返回值则async Task<T>    不返回则async Task

实验1:

使用Task.Delay(TimeSpan)担任耗时操作

第一课,理解什么时候Task和Task<T>,同步与异步

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

返现目前是同步的执行,而且AddNum画了绿色的线条,我们使用 .Result()拿到Task返回的值

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

Ok,缺少await运算符,我们使用Task.Delay延迟下,让它执行一个异步操作,此时AddNum方法没有了绿色,我们鼠标移到Delay方法上

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

返回的是Task,并不是Task<T> 所以此方法没有返回值.

(个人理解:如果 async 修饰的方法体中没有await操作等于没有加async的效果一样的,就是个普通的方法,只不过已经告诉编译器这可能是个异步方法,如果被await关键字调用的操作就是名副其实的异步方法了.

一个async方法有很多同步的方法组成,你的写法,最终是编译器把你的改成了老式的异步写法) 不理解没关系,先看完文章

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

我们注释刚刚的延迟操作,把操作放到另一个方法中-操作移出来:

 =============潇洒的版权线==========www.ayjs.net===== Aaronyang ========= AY =========== 安徽 六安 杨洋 ==========   未经允许不许转载 =========

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

await关键字只能用在async修饰的方法体内

这里没有用async方法的Result拿返回值了,因为await修饰了async的方法(个人理解:async表示该方法可以被异步的调用)

效果如下: C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

OK,接下来,我们再增加一个3倍操作的方法

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

await保证了代码的执行顺序,让代码不会出现一会3倍操作..一会2倍操作.而是很有顺序的执行

效果图: C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

ok,接下来我们增加一个在异步方法体里面console.writeline

 static async Task AddNumDouble2(int num)         {             //一个耗时的计算             await Task.Delay(TimeSpan.FromSeconds(1));             Console.WriteLine("AddNumDouble2方法中:" + num * 2);         }

修改AddNum方法如下:

static async Task<int> AddNum() {     int a=0;     for (int i = 0; i < 4; i++)     {  //var nextDelay = TimeSpan.FromSeconds(1);  //await Task.Delay(nextDelay);  //var result = await AddNumDouble(i);  //Console.WriteLine("2倍操作:"+result);  //var result2 = await AddNumThree(i);  //Console.WriteLine("3倍操作:" + result2);  await AddNumDouble2(i);  a++;     }     return  a; } 

效果图: C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

接下来我们去掉await关键字执行,让代码没有顺序

static async Task<int> AddNum() {     int a=0;     for (int i = 0; i < 4; i++)     {  //var nextDelay = TimeSpan.FromSeconds(1);  //await Task.Delay(nextDelay);  //var result = await AddNumDouble(i);  //Console.WriteLine("2倍操作:"+result);  //var result2 = await AddNumThree(i);  //Console.WriteLine("3倍操作:" + result2);  //await AddNumDouble2(i);  AddNumDouble2(i);  Console.WriteLine("www.ayjs.net开心就好"+i+"次");  a++;     }     return  a; } 

效果图:

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

此时你发现AddNumDouble2还没执行完, Console.WriteLine("www.ayjs.net开心就好"+i+"次");代码就执行了,而且for循环也执行完了,而且AddNumDouble2中的内容输出也没有顺序,是0642,而不是0246

实验2(简单的实战)

新建一个WPF程序或者winform程序,这里我用wpf.

界面很简单,一个文本框,一个按钮,按钮的Click事件如下:

第一种代码:

public int SyncAddNumDouble(int num) {  //一个耗时的计算  Thread.Sleep(1000);  return num * 2; } private void Button_Click(object sender, RoutedEventArgs e) {  int sum = 0;  for (int i = 0; i < 4; i++)  {     var result=SyncAddNumDouble(i);     sum += result;  }  txtResult.Text = sum.ToString(); } 

效果如下:你会发现窗体在后台执行耗时操作时候,根本卡死,执行完后,才能响应.

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

我们继续修改代码:

public async Task<int> SyncAddNumDouble(int num) {  //一个耗时的计算  await Task.Delay(1000);  return num * 2; } public async Task ImportData() {  int sum = 0;  for (int i = 0; i < 4; i++)  {   var result = await SyncAddNumDouble(i);   sum += result;  }  txtResult.Text = sum.ToString(); } private void Button_Click(object sender, RoutedEventArgs e) {  ImportData();  } 

效果图:发现在点击了导入之后,UI线程没有被阻塞,还是可以想干嘛就干嘛,这样才是我们的想要的,这就是异步的效果

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

当然不是说backgroundworker,Dispatcher方案就不是不可以了,都可以的.

如果你要进行的操作不支持await修饰怎么办? 使用Task.Factory.StartNew()就可以了,我们继续修改代码

public int SyncAddNumDouble(object num1) {  int num = (int)num1;  //一个耗时的计算  Thread.Sleep(1000);  return num * 2; } public async Task ImportData() {  int sum = 0;  for (int i = 0; i < 4; i++)  {   var result = await Task.Factory.StartNew((Func<object, int>)SyncAddNumDouble, i);   sum += result;  }  txtResult.Text = sum.ToString(); } private void Button_Click(object sender, RoutedEventArgs e) {  ImportData();  } 

效果同上,不附加图片了.

让DEMO更佳完善,Command的新的配合思路

这里首先我们需要一个辅助类

namespace Ay.Framework.WPF.Shared {  using System;  using System.Windows.Input;  public class DelegateCommand : ICommand  {   private readonly Action execute;   private readonly Func<bool> canExecute;   public DelegateCommand(Action execute)    : this(execute, null)   {   }   public DelegateCommand(Action execute, Func<bool> canExecute)   {    if (execute == null)    {     throw new ArgumentNullException("execute");    }    this.execute = execute;    this.canExecute = canExecute;   }   public event EventHandler CanExecuteChanged   {    add    {     if (canExecute != null)     {      CommandManager.RequerySuggested += value;     }    }    remove    {     if (canExecute != null)     {      CommandManager.RequerySuggested -= value;     }    }   }   public void RaiseCanExecuteChanged()   {    CommandManager.InvalidateRequerySuggested();   }   public bool CanExecute(object parameter)   {    return canExecute == null ? true : canExecute();   }   public void Execute(object parameter)   {    execute();   }  } } 

我都是手动MVVM的,新建一个ViewModelBase

public class ViewModelBase : INotifyPropertyChanged {  public event PropertyChangedEventHandler PropertyChanged;  protected void OnPropertyChanged(string property)  {   var handler = PropertyChanged;   if (handler != null)   {    handler(this, new PropertyChangedEventArgs(property));   }  } } 

OK,准备就绪,我们写一个MainWindow对应的ViewModel类,也就是MainViewModel

 public class MainViewModel : ViewModelBase     {            }

接下来在MainViewModel中我们增加一个

 public ICommand ImportDataCommand { get; set; }

在构造函数中,绑定对应的实现,由于对应的ViewModel无法拿到window的控件,为了让最终值的文本显示,我们需要添加一个自动通知的属性

private string importResult; public string ImportResult {  get  {   return this.importResult;  }  set  {   this.importResult = value;   OnPropertyChanged("ImportResult");  } } 

把刚刚第一个版本的操作代码迁移过来,并修改那个文本框的Text代码,换成 ImportResult的赋值,并把Task的返回值换成void

public async Task<int> SyncAddNumDouble(int num) {  //一个耗时的计算  await Task.Delay(1000);  return num * 2; } private async void ImportData() {  int sum = 0;  for (int i = 0; i < 4; i++)  {   var result = await SyncAddNumDouble(i);   sum += result;  }  ImportResult = sum.ToString(); } 

然后构造函数,绑定这个异步方法

 public MainViewModel()         {            this.ImportDataCommand = new DelegateCommand(this.ImportData);         }

OK,目前为止ViewModel算写完了,很简单吧,我们打开MainWindow,按照MVVM的写法,都是讲ViewModel赋予窗体的DataContext

 public MainWindow()         {             InitializeComponent();            this.DataContext = new MainViewModel();         }

而窗体对应的xaml中 都是binding对应ViewModel能绑定的东西,绑定吧!!!

<Window x:Class="WpfApplication1.MainWindow"  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" WindowStartupLocation="CenterScreen"  Title="www.ayjs.net aaronyang" Height="350" Width="525">     <Grid>  <Button Content="导入数据" HorizontalAlignment="Left" Command="{Binding ImportDataCommand}" Margin="133,32,0,0" VerticalAlignment="Top" Width="190" Height="26"/>  <TextBox x:Name="txtResult" HorizontalAlignment="Left" Height="24" Margin="133,87,0,0" TextWrapping="Wrap" Text="{Binding ImportResult}" VerticalAlignment="Top" Width="210"/>     </Grid> </Window> 

运行吧! 效果一样,主窗体没有阻塞,效果照样能运行.

C#人爱学不学9[C#5.0异步实例+WPF自己的MVVM Async应用 1/12]

好了,今天的内容现讲到这里

       =============潇洒的版权线==========www.ayjs.net===== Aaronyang  ========= AY =========== 安徽 六安 杨洋 ==========   未经允许不许转载 =========

-------------------小小的推荐,作者的肯定,读者的支持。推不推荐不重要,重要的是希望大家能把WPF推广出去,别让这么好的技术消失了,求求了,让我们为WPF技术做一份贡献。-----------------

  • 上一篇: WPF开发的,win7,win8,xp默认主题的更改
  • 下一篇:

猜你喜欢

  • WPF开发的,win7,win8,xp默认主题的更改 2015-04-14
  • 写给自己的WPF4.5行为总结 2015-04-10
  • WPF技巧经验帖 2015-04-07
  • WPF开源库收藏 2015-04-01
  • Ay.Framework.WPF 2.0建立项目到底有多快[1] 2015-03-31
  • 只需要几行xaml,实现一个水印文本框 2015-03-30
  • AyTabControlBase样式分享 2015-03-27
  • [Aaronyang] 写给自己的WPF4.5 笔记24 [与winform交互-flash-DEMO-收尾篇1/6] 2015-03-18
  • [Aaronyang] 写给自己的WPF4.5 笔记23 [3d交互与动画 4/4] 2015-03-17
  • [Aaronyang] 写给自己的WPF4.5 笔记22 [3d交互与动画 3/4] 2015-03-17
正文到此结束
Loading...