代码改变世界

Winfrom界面异步操作的一个解决方法

2009-07-21 21:44  Animax!  阅读(2573)  评论(4编辑  收藏  举报

首先定义为界面需要两个部分:

1、界面的逻辑操作部分
2、界面显示部分


基本思路如下:
界面逻辑操作部分提供支持方法以及支持方法列表。
界面显示部分主动触发逻辑操作,并把操作完成后界面操作内容封装为一个闭包传入逻辑操作部分。
界面逻辑操作在每次操作完成后激发界面显示部分闭包的操作内容。

下面就定义一个界面逻辑操作的基类来处理异步的操作:


    public class ViewOperation

    {

        private class ActionEventState

        {

            public ActionEventState()

            {

                IsEndInvoke = false;

            }

            public Guid EventID { getset; }

            public Control View { getset; }

            public LogicActionHandler handler { getset; }

            public object CallBackValue { getset; }

            public bool IsEndInvoke { getset; }

        }

        protected delegate object LogicActionHandler(object data);

        public delegate void ActionCallBack(object ActionState);

        protected Dictionary<stringLogicActionHandler> ActionHandlerList = new Dictionary<stringLogicActionHandler>();

        private Dictionary<GuidActionCallBack> _actionCallBackList = new Dictionary<GuidActionCallBack>();

        /// <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中报错。