您的位置:首页 > 其它

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

2011-09-27 10:16 381 查看
在 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);
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐