Winfrom界面异步操作的一个解决方法
2009-07-21 21:44 Animax! 阅读(2573) 评论(4) 编辑 收藏 举报
首先定义为界面需要两个部分:
1、界面的逻辑操作部分
2、界面显示部分
基本思路如下:
> 界面逻辑操作部分提供支持方法以及支持方法列表。
> 界面显示部分主动触发逻辑操作,并把操作完成后界面操作内容封装为一个闭包传入逻辑操作部分。
> 界面逻辑操作在每次操作完成后激发界面显示部分闭包的操作内容。
下面就定义一个界面逻辑操作的基类来处理异步的操作:
public class ViewOperation
{
private class ActionEventState
{
public ActionEventState()
{
IsEndInvoke = false;
}
public Guid EventID { get; set; }
public Control View { get; set; }
public LogicActionHandler handler { get; set; }
public object CallBackValue { get; set; }
public bool IsEndInvoke { get; set; }
}
protected delegate object LogicActionHandler(object data);
public delegate void ActionCallBack(object ActionState);
protected Dictionary<string, LogicActionHandler> ActionHandlerList = new Dictionary<string, LogicActionHandler>();
private Dictionary<Guid, ActionCallBack> _actionCallBackList = new Dictionary<Guid, ActionCallBack>();
/// <summary>
/// 异步操作执行
/// </summary>
public void DoAction(Control view, string ActionKey, object Data, ActionCallBack callBack)
{
Guid EventID = Guid.NewGuid();
_actionCallBackList.Add(EventID, callBack);
if (ActionHandlerList.ContainsKey(ActionKey))
{
LogicActionHandler handler = ActionHandlerList[ActionKey];
var i = handler.BeginInvoke(Data, ActionCallback, new ActionEventState() { EventID = EventID, View = view, handler = handler });
}
}
private void ActionCallback(IAsyncResult ar)
{
ActionEventState state = (ActionEventState)ar.AsyncState;
if (!state.IsEndInvoke)
{
object callBackValue = state.handler.EndInvoke(ar);
state.CallBackValue = callBackValue;
state.IsEndInvoke = true;
}
if (state.View.InvokeRequired)
{
state.View.Invoke(new AsyncCallback(ActionCallback), new object[] { ar });
}
else
{
// 回调
if (_actionCallBackList.ContainsKey(state.EventID))
{
try
{
if (_actionCallBackList[state.EventID] != null)
_actionCallBackList[state.EventID](state.CallBackValue);
}
catch (Exception ex)
{
// TODO : 错误处理
}
finally
{
_actionCallBackList.Remove(state.EventID);
}
}
}
}
}
使用Demo:
逻辑操作的类,需要注册它所拥有的方法:
public class Viewlogic : ViewOperation
{
public Viewlogic()
{
base.ActionHandlerList.Add("SomeOperation", new LogicActionHandler(SomeOperation));
}
private object SomeOperation(object data)
{
Thread.Sleep(Convert.ToInt32(data.GetType().GetProperty("waitTime").GetValue(data, null)));
return data.GetType().GetProperty("Msg").GetValue(data, null).ToString();
}
}
界面调用,按照方法的Key调用改方法:
new Viewlogic().DoAction(this, "SomeOperation",
new
{
waitTime = 2000,
Msg = "viewMsg"
},
new ViewOperation.ActionCallBack(o =>
{
MessageBox.Show(o.ToString());
}));
这个方法的缺点:
> 界面和逻辑数据传递就依靠一个object,界面需要知道传入的数据和放回的数据。
> 界面需要知道能调用的方法。这个虽然是在一个列表中,可以在逻辑类中列出他拥有的方法,但是在开发时没有环境支持。
> 在回调过程中界面出现错误,VS是会在ViewOperation中报错。