在Silverlight中对多个异步任务的调用 http://www.cnblogs.com/chenxizhang/archive/2011/08/30/2159124.html
来源:互联网 发布:t局域网通讯软件 编辑:程序博客网 时间:2024/06/05 16:22
这是一个常见的问题,由于Silverlight只支持异步调用后台的服务,而如果有多个任务的话,可能就很麻烦,往往就是要在一个异步任务结束事件中去调用另外一个任务,以此类推。典型的问题就是,代码很复杂,而且几乎很难维护。看看下面的代码吧
//传统的多个异步任务的调用方法,必须是一层一层嵌套的方式 var proxy = new ServiceReference1.WebService1SoapClient(); proxy.Endpoint.Address = new System.ServiceModel.EndpointAddress( new Uri(App.Current.Host.Source, "../WebService1.asmx")); proxy.HelloWorldCompleted += (o, a) => { proxy.GetEmployeeCompleted += (o1, a1) => { proxy.GetCustomersCompleted += (o2, a1) => { }; proxy.GetCustomersAsync(); }; proxy.GetEmployeeAsync(); }; proxy.HelloWorldAsync();
为了解决这个问题,我自己也想过一些办法,同时参考了张志敏的如下文章
http://www.cnblogs.com/beginor/archive/2010/12/24/1915910.html
这篇文章提供了一个不错的思路。这篇文章的评论中,有朋友也提到了Reactive Framework,我看了看,还没有找到很好的应用方法。这个Framework是一个很强大的东西,但在本文讨论的场景中具体该如何应用,如果有这方面研究的朋友,请不吝赐教
在这篇文章提供的简单模型基础上,我做了一些修改,并且也增加了一些更加实用的特性。共享出来给大家参考
添加和改进的功能主要是:
1.使用更加便捷(原先是用IEnumerator去构造Runner,现在提供了更多的支持,可以是一个Array,也可以是一个List等等,因为我们很多时候任务是动态构造出来的)
2.提供了任务结果反馈(ActionResult)的功能
3.提供了任务之间约束的功能,在每个任务里面都可以得到前置任务的信息
如何使用?
第一步:添加Nuget Package,关于什么是Nuget,请参考 http://www.cnblogs.com/dudu/archive/2011/07/15/nuget.html
第二步,参考如下的范例代码
运行效果
完整源代码
如果你不想下载包,可以直接复制这个代码进行使用或者修改
using System;using System.Collections.Generic;using System.Linq;/* * 这个设计针对在Silverlight中经常需要对多个远程服务进行调用,而且我们可能需要让这些任务之间有固定的顺序,同时还希望能够在任务之间传递任务状态,还支持进度汇报的功能 * 作者:陈希章 * 时间:2011年8月30日 * 反馈:ares@xizhang.com */#region Sample Code ////第一个任务 //var task = new AsyncAction("Task 1"); //task.SetAction(() => //{ // var proxy = new ServiceReference1.WebService1SoapClient(); // proxy.Endpoint.Address = new System.ServiceModel.EndpointAddress( // new Uri(App.Current.Host.Source, "../WebService1.asmx")); // proxy.HelloWorldCompleted += (o, a) => // { // task.ActionResult.Message = "Test test"; // task.ActionResult.Result = a.Result; // task.ActionResult.Status = ActionStatus.Success; // task.OnCompleted(); // }; // proxy.HelloWorldAsync(); //}, true); ////第二个任务 //var task2 = new AsyncAction("Task 2"); //task2.SetAction(() => //{ // var proxy = new ServiceReference1.WebService1SoapClient(); // proxy.Endpoint.Address = new System.ServiceModel.EndpointAddress( // new Uri(App.Current.Host.Source, "../WebService1.asmx")); // proxy.HelloWorldCompleted += (o, a) => // { // task2.ActionResult.Message = "Test test"; // task2.ActionResult.Result = a.Result; // task2.ActionResult.Status = ActionStatus.Success; // task2.OnCompleted(); // }; // proxy.HelloWorldAsync(); //}, true); ////构造Runner //var runner = new AsyncActionRunner(new[] { task, task2 }); ////注册完成事件 //runner.Completed += (o, a) => //{ // //将界面设置为空闲 // busyIndicator.IsBusy = false; // //显示所有任务的执行结果 // dgResult.ItemsSource = runner.TaskResults; //}; //runner.ProgressChanged += (o, a) => //{ // busyIndicator.BusyContent = string.Format("Current Step :{0}, Percent:{1:p}, Name:{2},Status:{3}", a.Current, a.Percent, a.ActionResult.TaskName, a.ActionResult.Status); //}; ////将界面设置为忙碌 //busyIndicator.IsBusy = true; ////执行 //runner.Execute();#endregionnamespace System{ /// <summary> /// 这个枚举记录了任务的状态,默认为Ready /// </summary> public enum ActionStatus { Ready,//准备好,如果最后检查仍然为这个状态,则通常表示该任务被跳过了 Success,//成功 Failure,//失败 Completed//完成 } /// <summary> /// 这个记录了任务的结果 /// </summary> public class ActionResult { public ActionResult() { Status = ActionStatus.Ready;//默认为ready StartTime = DateTime.Now; } /// <summary> /// 任务名称 /// </summary> public string TaskName { get; set; } /// <summary> /// 状态 /// </summary> public ActionStatus Status { get; set; } /// <summary> /// 消息 /// </summary> public string Message { get; set; } /// <summary> /// 任务结果 /// </summary> public object Result { get; set; } /// <summary> /// 开始时间 /// </summary> public DateTime StartTime { get; set; } /// <summary> /// 结束时间 /// </summary> public DateTime EndTime { get; set; } } /// <summary> /// 异步任务的接口 /// </summary> public interface IAsyncAction { void Execute(); event EventHandler Completed; ActionResult PreActionResult { get; set; } ActionResult ActionResult { get; set; } string TaskName { get; set; } } /// <summary> /// 异步任务的实现类型 /// </summary> public class AsyncAction : IAsyncAction { public AsyncAction(string name):this() { TaskName = name; } public AsyncAction() { ActionResult = new ActionResult(); } private bool AutoComplete = false; private Action Action { get; set; } /// <summary> /// 设置要执行的操作 /// </summary> /// <param name="action">操作</param> /// <param name="autoComplete">是否自动完成</param> public void SetAction(Action action, bool autoComplete) { Action = action; AutoComplete = autoComplete; } public virtual void Execute() { if(Action != null) { ActionResult.StartTime = DateTime.Now; Action(); if(!AutoComplete) OnCompleted(); } } public event EventHandler Completed; public void OnCompleted() { var completed = this.Completed; if(completed != null) { completed(this, EventArgs.Empty); } } /// <summary> /// 前置任务的结果,添加这个功能目的是,可能多个任务之间互相有所依赖,例如某个任务要根据前面任务的情况决定是否执行 /// </summary> public ActionResult PreActionResult { get; set; } /// <summary> /// 当前任务的结果 /// </summary> public ActionResult ActionResult { get; set; } /// <summary> /// 任务名称 /// </summary> private string taskName = string.Empty; public string TaskName { get { return taskName; } set { taskName = value; ActionResult.TaskName = value; } } } /// <summary> /// 任务运行器 /// </summary> public class AsyncActionRunner { public AsyncActionRunner() { TaskResults = new List<ActionResult>(); } private readonly IEnumerator<IAsyncAction> _enumerator; private int taskCount = 0; //public AsyncActionRunner(IEnumerator<IAsyncAction> enumerator) // : this() //{ // this._enumerator = enumerator; //} public AsyncActionRunner(IList<IAsyncAction> tasks) : this() { taskCount = tasks.Count(); _enumerator = tasks.GetEnumerator(); } /// <summary> /// 完成事件及处理方法 /// </summary> public event EventHandler Completed; /// <summary> /// 进度发生更改时发生 /// </summary> public event EventHandler<ProgressEventArgs> ProgressChanged; /// <summary> /// 保存所有任务的执行结果 /// </summary> public List<ActionResult> TaskResults { get; private set; } /// <summary> /// 临时保存的当前任务的执行结果 /// </summary> private ActionResult tmp = null; private int index = 1; /// <summary> /// 执行所有任务 /// </summary> public void Execute() { if(this._enumerator.MoveNext()) { var current = this._enumerator.Current; tmp = current.ActionResult; var ci = index++; current.Completed += (sender, args) => { tmp = ((IAsyncAction)sender).ActionResult; tmp.EndTime = DateTime.Now; TaskResults.Add(tmp); if(ProgressChanged != null) { ProgressChanged(this, new ProgressEventArgs(ci, (double)ci / taskCount, tmp)); } this.Execute(); }; current.PreActionResult = tmp; current.Execute(); ProgressChanged(this, new ProgressEventArgs(ci, (double)ci / taskCount, tmp)); } else { index = 1;//将进度复位 var completed = this.Completed; if(completed != null) { completed(this, EventArgs.Empty); } } } } /// <summary> /// 进度事件的参数 /// </summary> public class ProgressEventArgs : EventArgs { public int Current { get; set; } public ActionResult ActionResult { get; set; } public ProgressEventArgs(int current, double percent, ActionResult result) { this.Current = current; ActionResult = result; Percent = percent; } public double Percent { get; set; } }}更多请查看陈希章博客http://www.cnblogs.com/chenxizhang/archive/2011/08/30/2159124.html
- 在Silverlight中对多个异步任务的调用 http://www.cnblogs.com/chenxizhang/archive/2011/08/30/2159124.html
- 网络编程之TCP/UDP及其流程比较 http://www.cnblogs.com/chenxizhang/archive/2009/04/14/1435777.html
- 一些在JAVA中获得文件夹路径的方法http://www.cnblogs.com/lostyue/archive/2011/06/27/2091686.html
- _exit和exit的区别 http://www.cnblogs.com/hnrainll/archive/2011/08/17/2142001.html
- ajax异步上传带文件的表单 http://www.cnblogs.com/gaojun/archive/2012/08/11/2633891.html
- 对WebService的一些封装技巧总结(http://www.cnblogs.com/sxwgf/archive/2011/07/10/something-about-webservice.html
- 分享42个精美的免费PSD素材(转http://www.cnblogs.com/lhb25/archive/2011/02/22/1960203.html)
- HTTP协议的chunked编码 http://www.cnblogs.com/zhaozhan/archive/2010/08/24/1807639.html
- WinForm/Silverlight多线程编程中如何更新UI控件的值(http://www.cnblogs.com/yjmyzz/archive/2009/11/25/1610253.html)
- C++中delete和delete[]的区别 http://www.cnblogs.com/charley_yang/archive/2010/12/08/1899982.html
- Java中getResourceAsStream的用法(转自:http://www.cnblogs.com/javayuer/archive/2011/01/02/1924192.html)
- Android中gravity与layout_gravity的区别 http://www.cnblogs.com/linjiqin/archive/2011/02/20/1959239.html
- PHP中spl_autoload_register函数的用法 ---转载自http://www.cnblogs.com/myluke/archive/2011/06/25/2090119.html
- 超有营养的好博客http://www.cnblogs.com/me115/archive/2012/09/08/2676250.html
- 超有营养的好博客http://www.cnblogs.com/me115/archive/2012/09/08/2676250.html
- Android Fragment的使用http://www.cnblogs.com/xinye/archive/2012/08/28/2659712.html
- Hadoop的运行痕迹http://www.cnblogs.com/JohnLiang/archive/2011/11/9.html
- 有关select的操作http://www.cnblogs.com/dcba1112/archive/2011/05/26/2057551.html
- Particle System(粒子系统)
- 关于Sliverlight4 打印功能
- 怎样度量信息
- 49. All things is difficult before they are easy. 凡事总是由难而易
- 自制Silverlight页面跳转缓存
- 在Silverlight中对多个异步任务的调用 http://www.cnblogs.com/chenxizhang/archive/2011/08/30/2159124.html
- 获取字符串中的字母
- SilverLight-摄像头捕获图像案例
- Silverlight中DataGrid控件动态生成列并结合DataPager进行分页
- WINDOW7蓝屏错误代码、使用常见问题、解决方法汇总
- Silverlight中的导航总结
- 一个简单的小程序演示Unity的三种依赖注入方式
- windows phone7 下 Silverlight 异步读取网络图片
- 布尔代数和搜索引擎的索引