惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Apple Machine Learning Research
Apple Machine Learning Research
T
Tailwind CSS Blog
月光博客
月光博客
爱范儿
爱范儿
有赞技术团队
有赞技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
aimingoo的专栏
aimingoo的专栏
GbyAI
GbyAI
腾讯CDC
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
MongoDB | Blog
MongoDB | Blog
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
云风的 BLOG
云风的 BLOG
U
Unit 42
博客园 - 三生石上(FineUI控件)
A
About on SuperTechFans
N
Netflix TechBlog - Medium
Google DeepMind News
Google DeepMind News
雷峰网
雷峰网
L
LangChain Blog

博客园 - xiaosonl

学习手札#3 NHibernate缓存 产品的简单性 关于过度设计的思考(上) 让ASP.NET MVC的Controller输出不同类型数据 学习手札#2 故事点和小时数的思考 学习笔记#1 键值对数据库 SQLite数据迁移 探讨一种在Silverlight不普及情况下的部署策略 有用的文档 Silverlight产品布署策略 代码的注释 下半年要看完消化的技术类书籍 中小型企业的人员流失 谈谈Ruby On Rails和ASP.NET 工作中的系统学习 Uml中的关联与依赖关系 TDD与重构设计 C#中使用位运算来实现权限管理 Silverlight中JavaSciprt无法访问托管类抽象成员的解决方法
探讨一种Silverlight的异步编程模式
xiaosonl · 2010-03-27 · via 博客园 - xiaosonl

2010-03-27 16:14  xiaosonl  阅读(1030)  评论()    收藏  举报

在开发RIA程序时,处理异步操作是个挺麻烦的问题,尤其是串行的异步调用,经常代码会写的嵌套好几层。之前老赵也介绍过一种方法来简化异步操作。我这是另一种思路。

在之前的Silverlight程序开发过程中,我的编程模式是这样的:

  1. 用户执行一个UI操作,并引发UI事件,此时在UI线程开始执行后台代码。
  2. 在代码执行过程中,遇到需要异步的操作,如网络请求等,就在另一个线程执行该操作,执行完毕后利用事件或委托继续执行接下来的操作。如果这时异步操作比较多,就会有很多的事件或委托跳来跳去的,很不好看。

这时我们可以换一种思路,反过来做,每一次的操作,我们都发起一个新的线程来执行,不再从UI线程发起。执行过程中遇到的异步操作(网格请求,或者UI操作,因为这时UI有关的操作都必须使用BeginInvoke来调用),可以用ResetEvent来阻塞住发起操作的线程,异步操作执行结束后再继续 因为一开始是在非UI线程中发起操作,所以不会阻塞UI。

总结一下:

  1. 每个操作都是发起一个新的线程来执行。
  2. 每个异步方法都可以用ResetEvent来模拟成同步方法,就可以很方便像同步方法那样调用和组织, 但在简单的异步场景中优势不明显。
  3. 缺点是影响性能,用性能来换代码的可读性和可维护性。

最后附上一个简易示例代码(未经运行测试和优化),演示将[下载数据 => 处理数据并更新UI] 的过程模拟成同步操作:

代码

    public partial class MainPage : UserControl
    {
        
public MainPage()
        {
            InitializeComponent();
        }
private void btnCommand_Click(object sender, RoutedEventArgs e)
        {
            Command();
        }
//执行操作
        public void Command()
       {
            ThreadPool.QueueUserWorkItem(t 
=>
            {
                UIInvoke(() 
=>
                { 
                    
//弹出一个ProgressBar,提示操作正在进行中
                  });//下载数据
                string downloadData = DownLoad();
                
//更新UI
                UIInvoke(() => txtMessage.Text = downloadData);

                UIInvoke(() 

=>
                {
                    
//关闭ProgressBar,提示操作结束
                });
            });
        }
//以同步的方式调用UI线程执行一个操作
        private void UIInvoke(Action action)
       {
            Dispatcher dispatcher 
= Deployment.Current.Dispatcher;if (dispatcher.CheckAccess())
            {
                action();
            }
            
else
            {
                ManualResetEvent resetEvent 
= new ManualResetEvent(false);
                resetEvent.Reset();
                dispatcher.BeginInvoke(() 
=>
                {
                    action();
                    resetEvent.Set();
                });
                resetEvent.WaitOne();
            }
        }
private string DownLoad()
        {
            ManualResetEvent reset 
= new ManualResetEvent(false);
            reset.Reset();
            
//下载数据
            WebClient client = new WebClient();
            
string result = "";
            client.DownloadStringCompleted 
+= (s, e) =>
            {
                result 
= e.Result;
                reset.Set();
            };
            client.DownloadStringAsync(
new Uri("http://下载地址"));
            reset.WaitOne();
return result;
        }
    }