讨论 winform 引擎以及 CancelButton,OKButton 的实现原理
前面提到了form关闭时的两个奇怪现象,有不少朋友参与了讨论。
有些朋友还没有看清楚问题的所在就很轻率的评论。
A.Z. 在讨论中已经找到的问题的基本所在,问题关键还是在 CalledClosing 这个变量的状态。
这个问题要从另外一个奇怪现象说起。
为什么直接给 form的DialogResult属性赋值会导致form关闭?
这个属性的set函数如下:
public void set_DialogResult(DialogResult value)
{
if (!ClientUtils.IsEnumValid(value, (int) value, 0, 7))
{
throw new InvalidEnumArgumentException("value", (int) value, typeof(DialogResult));
}
this.dialogResult = value;
}
很明显,这个set函数不可能直接导致 form的关闭。
再回头看前面的第二个奇怪现象,不发生closing事件,但是仍然发生closed事件。
如是我在closed事件中查看函数调用堆栈,发现入口函数是 CheckCloseDialog 函数。
和 A.Z. 提到的一样,按照这个方式理解,那只有一个可能,就是 CalledClosing 的值为 true。
所以不会发生 Closing 事件,可是前面讨论也提到了 在函数 WmClose 调用 CheckCloseDialog 之前
已经给CalledClosing 赋值 false 了。
如是猜想,会不会还有其它函数调用 CheckCloseDialog 了?
用reflector的搜索,发现
private bool LocalModalMessageLoop(Form form)
函数每次循环都会调用这个函数。
当时讨论一直忽略了另外一个重要的东西,就是这个窗口的消息循环过程。
form的所有事件驱动都是从这里发出的。
这就清楚为什么直接给form的DialogResult属性赋值会导致 form关闭了,
因为有一个循环一直在哪里判断 DialogResult的值,如果不是None,就会进入关闭处理过程。
form的CancelButton和OKButton的原理,msdn中有介绍。
CancelButton的作用就是在 用户 按 ESC 键是 触发这个按钮的Click 事件。
OKButton的作用是用户按 Enter键是触发这个按钮的click事件。
除此之外它们和 form上的其它按钮没有什么区别。
有的朋友可能会说,form的CancelButton和OKButton点击后会导致 form关闭。
其实Form关闭和它们是否CancelButton或者OKButton没有直接关系。
感兴趣的朋友可以试试,把一个button设置 form的cancelbutton,然后再把form的
cancelbutton设置为none。
然后会发现之前设置为cancelbutton的按钮被点击后,仍然会导致 form 关闭。
导致form关闭的直接原因是 button的 dialogresult属性,button的默认点击事件处理函数
会将 button的DialogResult属性赋值给它所在的form。
消息循环检测到DialogResult后就引起form关闭了。
这可能是 form设计器的一个bug。当你将一个button设置为cancelbutton时,设计器会给
这个button的DialogResult设置为 Cancel,当你取消cancelbutton设置时,设计器不会修改
button的DialogResult设置值。
任何一个form上的按钮,当设置它的DialogResult属性后,其被点击都会引起form的关闭。
如何在这类按钮的点击事件中阻止form关闭?
知道form的引擎执行原理后,很容易就知道方法了。
既然是按钮的默认点击事件处理函数设置了DialogResult值,我们在点击事件里面再重写
DialogResult值就行了。
再回头看上一次的第二个问题,
因为CancelButton是通过设置DialogResult进入form关闭处理过程的(直接从消息循环进入CheckCloseDialog)
前一次非正常流程导致CalledClosing 值设置为 true了。所以没有发生 closing事件。
而点击 X'按钮,是从 WMClose 进入的关闭过程,在wmclose里面总是会将 CalledClosing 的值设置为false。
所以会发生closing事件。
这里我们又知道了另一种在closing事件中阻止form关闭的方法。
常规的方法是将 e.Cancel设置为 true。
这里测试出来的方法是将 DialogResult设置为 None。
实际上影响form关闭的是 DialogResult 的值。
注:以上针对的是模态的form,对于非模态的form有另外一个类似的消息循环处理过程。
posted on 2007-09-24 18:03 紫雨轩 .Net 阅读(2966) 评论(14) 编辑 收藏 举报