且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在Windows窗体中加载与显示的事件

更新时间:2023-12-06 17:02:52

避免使用MessageBox.Show()调试这个。它泵送消息循环,扰乱事件的正常流动。由Windows发送WM_SHOWWINDOW消息触发加载事件,就在窗口可见之前。没有Windows通知,您的窗口现在完全显示,所以WF设计师想出了一个技巧来生成显示事件。他们使用Control.BeginInvoke(),一旦程序再次空闲并重新进入消息循环,就可以确保OnShown()方法被调用。



这个技巧有许多其他用途,特别是当您必须延迟执行由事件开始的代码时。但是,在您的情况下,它会因为使用MessageBox.Show()而分崩离析。它的消息循环调度注册BeginInvoke()的代理,导致显示事件在之前显示窗口。



有很多其他方法可以在MessageBox之外获得诊断。 Debug.Print()和Console.WriteLine()很方便,他们的输出将转到 Visual Studio输出窗口,而不会对正常事件触发序列造成任何不利影响。一个简单的断点也可以做奇迹。


Hopefully I'm just missing something obvious, but I'm trying to get my head around the differences between the Load and the Shown events in Windows Forms.

Traditionally, I've only used Load (or actually OnLoad, since I think it's cleaner to override a method than to rely on the designer to hook up an event on yourself), since that is available in all versions of .NET. With .NET 2.0 the Shown event was introduced.

Now, if you look at the descriptions for these in the MSDN documentation ("Load: Occurs before a form is displayed for the first time.", "Shown: Occurs whenever the form is first displayed.") it sounds like the Load event should occur, then the form should become visible, then the Shown event should occur; the combination of the two thereby letting you carry out some tasks both before and after the form is visible. Makes sense, right?

However, experimentation has shown that the Shown event invariably occurs before the Load event, whenever I try it (and both occur before the form becomes visible). And yet, when I google around whenever I discover a page that talks about the order these events are fired in, they always list the Load event being fired first.

Am I just going crazy, or have I missed something? (And if they do occur at about the same time, then why was the Shown event added in the first place?)

(My current solution for doing something both before and after showing the form is to use OnLoad for the "before showing" stuff and start a short-duration one-shot timer for the "after showing" stuff. Which works OK and reliably, but it's a bit ugly and I was hoping there was a cleaner solution. But it looks like the Shown event isn't it.)

Avoid using MessageBox.Show() to debug this. It pumps a message loop, disturbing the normal flow of events. The Load event is triggered by Windows sending the WM_SHOWWINDOW message, just before the window becomes visible. There is no Windows notification for "your window is now fully shown", so the WF designers came up with a trick to generate the Shown event. They use Control.BeginInvoke(), ensuring the OnShown() method gets called as soon as the program goes idle again and re-enters the message loop.

This trick has lots of other uses, particularly when you have to delay the execution of code started by an event. However, in your case it falls apart because you use MessageBox.Show(). Its message loop dispatches the delegate registered with BeginInvoke(), causing the Shown event to run before the window is shown.

There are lots of other ways to get diagnostics beyond MessageBox. Debug.Print() and Console.WriteLine() are handy, their output goes to the Visual Studio Output Window without having any detrimental effects on the normal event firing sequence. A simple breakpoint can do wonders too.