Sliverlight for Windows Phone 异步的一种解决方案


在 Windows Phone 中异步操作比较常见,我的方法很简单,两句话。这是第二句,它看上去是这样的:

MethodCall.Invoke(
() =>    // 这是一个Func<Object>,返回一个结果
{
        // 这是一个耗时1秒以上的操作,为了获得一个值,亦或是一个结果集,我写这个类的目的是我把http请求改写成了同步,所以这样会很方便,同样这个类不仅限于http请求。所有耗时、延时操作都可用。
        string result = BigFunction(); // List<string> results = BigFunction();
        return result;
},
(obj) =>    // 这是一个Action<Object>,处理返回结果
{
        // 获得了返回结果,这里是线程安全的,内部使用 Dispatcher.BeginInvoke 来调用
        MessageBox.Show(obj.ToString());
     // List<string> results = (List<string>)obj;
});

另附上 MethodCall.cs

using System;
using System.Threading;
public static class MethodCall
{
    static MethodCall() 
    {
        OnComplate += new ComplateCallBack((obj) => {
            System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => {
                _callBack.Invoke(obj);
            });
        });
    }
    private static event ComplateCallBack OnComplate;
    private delegate void ComplateCallBack(object result);

    private static Action<object> _callBack;
    public static void Invoke(Func<object> action, Action<object> callback)
    {
        _callBack = callback;
        ThreadStart t = new ThreadStart(() => {
            OnComplate(action.Invoke());
        });
        new Thread(t).Start();
    }
}

用例说明(2011-11-15 11:50 新增):

因为wp7中只有异步请求,如果想封装一个框架实现某些功能,而框架内需要用到http请求,我只能把它写成同步的,使用线程等待的机制实现了一个扩展方法:

 

    public static class WebRequestExt
{
const int DefaultTimeout = 2 * 60 * 1000; // 2 minutes timeout

public static Stream GetRequestStream(this WebRequest request)
{
using (AutoResetEvent done = new AutoResetEvent(false))
{
RequestState state = new RequestState();
state.request = (HttpWebRequest)request;

request.BeginGetRequestStream((ar) =>
{
RequestState rstate = (RequestState)ar.AsyncState;
rstate.streamResponse = rstate.request.EndGetRequestStream(ar);
done.Set();
}, state);
done.WaitOne(DefaultTimeout);
return state.streamResponse;
}
}

public static HttpWebResponse GetResponse(this WebRequest request, ref string errText)
{
using (AutoResetEvent done = new AutoResetEvent(false))
{
RequestState state = new RequestState();
state.request = (HttpWebRequest)request;
request.BeginGetResponse((ar) =>
{
RequestState rstate = (RequestState)ar.AsyncState;
HttpWebRequest rrequest = state.request;
try
{
rstate.response = (HttpWebResponse)request.EndGetResponse(ar);
Stream responseStream = state.response.GetResponseStream();
rstate.streamResponse = responseStream;
}
catch (Exception e)
{
rstate.exception = e;
}
done.Set();
}, state);
done.WaitOne(DefaultTimeout);
if (state.exception != null)
{
errText = state.exception.Message;
}
return state.response;
}
}
}

internal class RequestState
{
// This class stores the State of the request.
public HttpWebRequest request;
public HttpWebResponse response;
public Stream streamResponse;
public Exception exception;
public RequestState()
{
request = null;
streamResponse = null;
}
}

我在使用的时候就可以像这样

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.baidu.com/");
string errText = null;

// 这里直接获得百度首页的html
HttpWebResponse response = request.GetResponse(ref errText);
// 这样的同步方式,而不是使用begin,end模式,再到callback方法中去处理
// IAsyncResult result = request.BeginGetResponse(RequestCallBack, state);


基于这个方法,可以写出同步的http请求,那么我在用的时候每次都去new线程不是很方便,所以封装了这个方法,其实就是省去了一些代码而已,用的时候可以这样:

MethodCall.Invoke(
() =>
{
/*
* 实际上这段代码是在新线程里执行的,比如在Click事件里直接这样写,也不会阻塞线程
*/

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.baidu.com/");
string errText = null;
// 同步调用GetResponse方法
HttpWebResponse response = request.GetResponse(ref errText);

using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
// 返回http请求的结果
return sr.ReadToEnd();
}
},
(obj) =>
{
/*
* 这里通过MethodCall在内部执行完上面的方法后调用的,obj参数为上面方法的返回值
*/

// 那么这里就可以获得百度首页的html了
// 同样如果上面返回的是一个List<string>或者其他的对象
// 也可以(List<string>)obj或者(xxx)obj来转换,返回值是你可以决定的
// 当然这也可以改写为一个泛型版,类型转换也不用了
string html = obj.ToString();
MessageBox.Show(html);
});


posted @ 2011-09-27 10:16  YoungPay  阅读(2221)  评论(3编辑  收藏  举报