使用Task简化Silverlight调用Wcf(续)

上一篇使用Task简化Silverlight调用Wcf介绍了Silverlight下使用Task的一些方法,这篇继续改进一下。

改进生成工具的生成的方法

上次生成的代码如下,这些TaskAsync只是简单的包装一下Wcf的begin和end方法:

public Task DoWorkTaskAsync()
{
    return Task.Factory.FromAsync(this.Channel.BeginDoWork, this.Channel.EndDoWork, null);
}
public Task<DateTime> GetSerivceTimeTaskAsync()
{
    return Task<DateTime>.Factory.FromAsync(this.Channel.BeginGetSerivceTime, this.Channel.EndGetSerivceTime, null);
}

调用时需要手动去Wait():

private void OnGetTimeClick(object sender, RoutedEventArgs e)
{
    ThreadPool.QueueUserWorkItem(s =>
    {
        var task = _systemServiceClient.GetSerivceTimeTaskAsync();
        task.Wait();
        Dispatcher.BeginInvoke(() =>
        {
            MessageBox.Show(task.Result.ToString());
        });
    });
}

这次生成的方法连task1.Wait(); 也包含了,多生成一个方法来Wait:

public Task DoWorkTaskAsync()
{
    return Task.Factory.FromAsync(this.Channel.BeginDoWork, this.Channel.EndDoWork, null);
}
public void DoWork()
{
    var task = DoWorkTaskAsync();
    task.Wait();
}

public Task<DateTime> GetSerivceTimeTaskAsync()
{
    return Task<DateTime>.Factory.FromAsync(this.Channel.BeginGetSerivceTime, this.Channel.EndGetSerivceTime, null);
}
public DateTime GetSerivceTime()
{
    var task = GetSerivceTimeTaskAsync();
    task.Wait();
    return task.Result;
}

这样调用包含Wait的方法就直接返回结果了,而不是返回Task,再去Wait():

private void OnGetTimeClick(object sender, RoutedEventArgs e)
{
    ThreadPool.QueueUserWorkItem(s =>
    {
        var time = _systemServiceClient.GetSerivceTime();
        Dispatcher.BeginInvoke(() => MessageBox.Show(time.ToString()));
    });
}

UI同步技巧

调用Wcf和UI交互需要顺序进行是最平常的需求,这时需要与UI交互也有“同步”的能力。例如:

ThreadPool.QueueUserWorkItem(s =&gt;
{
    //调用Wcf
    var num = _systemServiceClient.GetNum(5);
    //UI对话框询问是否继续
    var result = childWin.ShowSync();
    if(result == false)
        return;

    var time = _systemServiceClient.GetSerivceTime();
    .......
});

如果是UI线程的话是不可以这样阻塞的,然而这里是后台线程,阻塞也是没所谓的,所以可以使用下面的方法来阻塞线程,来模拟同步:

public partial class TestChildWindow : ChildWindow
{
    private readonly ManualResetEvent _manualResetEvent;

    public TestChildWindow()
    {
        InitializeComponent();
        _manualResetEvent = new ManualResetEvent(false);
        Closed += (_, __) => _manualResetEvent.Set();
    }

    public bool? ShowSync()
    {
        if (Dispatcher.CheckAccess())
            throw new InvalidOperationException("ShowSync只能使用后台线程调用!");

        Dispatcher.BeginInvoke(Show);
        _manualResetEvent.Reset();
        _manualResetEvent.WaitOne();
        return DialogResult;
    }
    .........
}

这里使用ManualResetEvent类来等待,打开窗体后马上阻塞,直到子窗体Closed时通知结束,实现”同步“。

这里注意ShowSync的Dispatcher.CheckAccess()判断,明确只能再后台线程里调用。

示例:

private void OnMultiTaskClick(object sender, RoutedEventArgs e)
{
    var childWin = new TestChildWindow();
    ThreadPool.QueueUserWorkItem(s =>
    {
        const string format = "Num:{1},{0}{2},{0}Time:{3},{0}UserCount:{4},{0}ChildWinResult:{5}";
        var num = _systemServiceClient.GetNum(5);
        var str = _systemServiceClient.SayHiTo(num.ToString());
	//这里是“同步”的
        var result = childWin.ShowSync();

        var time = _systemServiceClient.GetSerivceTime();
        var all = _userServiceClient.GetAll();
        var msg = string.Format(format, Environment.NewLine, num, str, time, all.Count, result);
        Dispatcher.BeginInvoke(() => MessageBox.Show(msg));
    });
}
image

工具和测试源码

posted @ 2013-02-03 00:29  zhangweiwen  阅读(2067)  评论(0编辑  收藏  举报