Office中国论坛/Access中国论坛

标题: 【原创】RibbonButton点击事件的真实原理 [打印本页]

作者: faunus    时间: 2014-3-9 16:01
标题: 【原创】RibbonButton点击事件的真实原理
本帖最后由 faunus 于 2014-3-13 13:29 编辑

处理流程如下:
  1.     // MyButton.MyClick的真实处理情况是这样的:
  2.     // 首先,向外公布一个MyClick方法变量,对这个变量的操作支持add和remove操作.
  3.     // 当Add操作时(也就是从外边作+=操作时),将传入值写入一个列表,起个名字叫做事件列表.
  4.     // 在MyButton内部的消息处理过程WndProc中,当截获到WM_LBUTTONUP消息时,调用WmMouseUp方法处理.
  5.     // 在WmMouseUp实体中调用MyOnClick方法.
  6.     // 在MyOnClick实体中,从事件列表中取到方法实例handler并调用方法.
  7.     // MyButton.MyClick的工作原理与例4所描述的不同
  8.     // 1.方法变量MyClick没有直接用来存放外部的方法实例,而是象属性那样,存放在一个字段_myEvents中.
  9.     // 2.消息处理过程WndProc也没有MyClick的调用,而是在MyOnClick中调用方法字段.
  10.     // 从本质上讲WndProc还是处理了MyClick的,但实现思路上区别很大.
  11.     // 好像少了一个环节,MyClick在内部没实例化过.MyOnClick中进行了方法字段是否为空的判断.
  12.     // 这说明方法变量在内部不一定需要传入实例,只要内部调用时进行非空判断就可以了.
  13.     // 以上研究都是把方法变量当做一般变量来处理.
  14.     // delegate与消息循环结合,这就是我们看到的事件.
  15.     // 事件带来的效果,实现了一个对象将自己的方法公布给别人,并由别人进一步完善这个方法.
  16.     // 这又绕回到最开始举的例子:领导委托下属做某件事!
  17.     // 最初的例子委托用错了地方,把下属的方法定义了一个变量来调用.
  18.     // 应该是把领导这个对象内定义一个方法变量,由下属具体实现.
  19.     // 下一例重构最初的例子.
复制代码

消息处理过程如下:
【重载消息中心】
  1.         protected override void WndProc(ref Message m)
  2.         {
  3.             base.WndProc(ref m);
  4.             switch (m.Msg)
  5.             {
  6.                 case WM_LBUTTONUP:
  7.                     this.WmMouseUp(ref m, System.Windows.Forms.MouseButtons.Left, 1);
  8.                     break;
  9.             }
  10.         }
复制代码
【加工消息参数】
  1.         private void WmMouseUp(ref Message m, System.Windows.Forms.MouseButtons button, int clicks)
  2.         {
  3.             //验证状态、将传入的消息加工成事件参数
  4.             // ...
  5.             MouseEventArgs args = new MouseEventArgs(button, clicks, SignedLOWORD(m.LParam), SignedHIWORD(m.LParam), 0);
  6.             this.MyOnClick(args);
  7.         }
复制代码
【辅助函数】
  1.         private int SignedLOWORD(IntPtr n)
  2.         {
  3.             return (short)((int)((long)n) & 0xffff);
  4.         }

  5.         private int SignedHIWORD(IntPtr n)
  6.         {
  7.             return (short)(((int)((long)n) >> 0x10) & 0xffff);
  8.         }
复制代码

事件的定义部分:
【消息字段声明】
  1.         const int WM_LBUTTONUP = 0x202;

  2.         #region "字段声明"
  3.         EventHandlerList _myEvents;
  4.         object _eventClick = new object();
  5.         #endregion
复制代码
【事件的定义】
  1.         #region "属性定义"
  2.         public EventHandlerList MyEvents
  3.         {
  4.             get
  5.             {
  6.                 if (this._myEvents == null)
  7.                 {
  8.                     this._myEvents = new EventHandlerList();
  9.                 }
  10.                 return this._myEvents;
  11.             }
  12.         }
  13.         #endregion

  14.         #region "事件定义"
  15.         public event EventHandler MyClick
  16.         {
  17.             add
  18.             {
  19.                 Events.AddHandler(_eventClick, value);
  20.             }

  21.             remove
  22.             {
  23.                 Events.RemoveHandler(_eventClick, value);
  24.             }
  25.             //AsyncCallback
  26.             //Activator
  27.         }

  28.         #endregion
复制代码
【调用方法】
  1.         private void MyOnClick(EventArgs e)
  2.         {
  3.             EventHandler handler = (EventHandler)base.Events[_eventClick];
  4.             if (handler != null)
  5.             {
  6.                 handler(this, e);
  7.             }
  8.         }
复制代码
注意:这里的handler是一个委托,将执行所有注册方法的列表。

附件(完整代码):

[attach]53521[/attach]


作者: 紫电    时间: 2014-3-10 11:52
没有内容,弄没了吧
作者: tmtony    时间: 2014-3-10 21:15
是没有看到内容
作者: smrgh    时间: 2014-3-11 17:00
???
作者: 醉酒狂生    时间: 2014-3-11 17:07
老大是在逗我们玩?
作者: ET_ET    时间: 2014-3-13 12:34
隐身可见?
作者: Amas    时间: 2014-3-13 13:48
留个足迹,待日后学习.
作者: yjjcm    时间: 2014-3-13 14:07
占个位,便于以后查询
作者: llm4947    时间: 2015-1-9 20:45
#在这里快速回复#没有内容,弄没了吧




欢迎光临 Office中国论坛/Access中国论坛 (http://www.office-cn.net/) Powered by Discuz! X3.3