这是一个常见的问题,由于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();
#endregion
namespace
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
; }
}
}