.net Windows 窗体中的加载事件与显示事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/397121/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Load vs. Shown events in Windows Forms
提问by Miral
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.
希望我只是遗漏了一些明显的东西,但我正试图弄清楚Windows Forms 中的 Load 和 Shown 事件之间的差异。
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.
传统上,我只使用了 Load(或者实际上是 OnLoad,因为我认为重写方法比依赖设计者自己连接事件更干净),因为它在所有版本的 .NET 中都可用。.NET 2.0 引入了 Shown 事件。
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 soundslike 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?
现在,如果您查看 MSDN 文档中的这些说明(“加载:首次显示表单之前发生。”、“显示:首次显示表单时发生。”)听起来像是 Load 事件应该发生,那么表单应该变得可见,然后 Shown 事件应该发生;两者的结合使您可以在表单可见之前和之后执行一些任务。有道理吧?
However, experimentation has shown that the Shown event invariably occurs beforethe 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.
然而,实验表明 Shown 事件总是发生在Load 事件之前,无论何时我尝试它(并且两者都发生在窗体变得可见之前)。然而,当我在谷歌上搜索时,每当我发现一个讨论这些事件触发顺序的页面时,它们总是首先列出 Load 事件被触发。
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?)
我只是疯了,还是我错过了什么?(如果它们几乎同时发生,那么为什么首先添加 Shown 事件?)
(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.)
(我目前在显示表单之前和之后做某事的解决方案是将 OnLoad 用于“显示之前”的内容,并为“显示之后”的内容启动一个短时间的一次性计时器。它可以正常工作且可靠,但是它有点难看,我希望有一个更干净的解决方案。但看起来 Shown 事件不是这样。)
回答by Hans Passant
Avoid using MessageBox.Show() to debug this. It pumps a message loop, disturbing the normal flow of events. The Loadevent 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 Shownevent. They use Control.BeginInvoke(), ensuring the OnShown() method gets called as soon as the program goes idle again and re-enters the message loop.
避免使用 MessageBox.Show() 来调试它。它会产生一个消息循环,扰乱正常的事件流。该负载事件是由Windows发送WM_SHOWWINDOW消息,就在窗口变得可见触发。没有 Windows 通知“您的窗口现在已完全显示”,因此 WF 设计者想出了一个技巧来生成Shown事件。他们使用 Control.BeginInvoke(),确保一旦程序再次空闲并重新进入消息循环,就会调用 OnShown() 方法。
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 beforethe window is shown.
这个技巧还有很多其他用途,特别是当您必须延迟由事件启动的代码的执行时。但是,在您的情况下它会崩溃,因为您使用 MessageBox.Show()。它的消息循环调度使用 BeginInvoke() 注册的委托,导致 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 Windowwithout having any detrimental effects on the normal event firing sequence. A simple breakpointcan do wonders too.
除了 MessageBox,还有许多其他方法可以进行诊断。Debug.Print() 和 Console.WriteLine() 很方便,它们的输出进入Visual Studio 输出窗口,而不会对正常事件触发序列产生任何不利影响。一个简单的断点也可以创造奇迹。
回答by Krishnan
Here's the sequence of event I traced. May this will help others to decide how they would like to call or set their custom event handling
这是我追踪的事件序列。这可能会帮助其他人决定他们想要如何调用或设置他们的自定义事件处理
Events traced
Form - Client Size Changed : 8/14/2010 10:40:28 AM
Form - Control Added - button1 : 8/14/2010 10:40:29 AM
Form - Constructor : 8/14/2010 10:40:29 AM
Form - Handle Created : 8/14/2010 10:40:29 AM
Form - Invalidated : 8/14/2010 10:40:29 AM
Form - Form Load event : 8/14/2010 10:40:29 AM
Form - Loaded : 8/14/2010 10:40:29 AM
Form - Create Control : 8/14/2010 10:40:29 AM
Form - OnActivated : 8/14/2010 10:40:29 AM
Form - Shown : 8/14/2010 10:40:29 AM
Form - OnPaint : 8/14/2010 10:40:29 AM
Form - Invalidated : 8/14/2010 10:40:29 AM
Form - OnPaint : 8/14/2010 10:40:29 AM
事件追踪
表单 - 客户规模更改:8/14/2010 10:40:28 AM
表单 - 添加控件 - button1:8/14/2010 10:40:29 AM
表单 - 构造函数:8/14/2010 10:40:29 AM
表单 - 句柄创建 : 8/14/2010 10:40:29 AM
表单 - 无效 : 8/14/2010 10:40:29 AM
表单 - 表单加载事件 : 8/14/2010 10:40:29 AM
表单 -已加载:8/14/2010 上午 10:40:29
表单 - 创建控件:8/14/2010 上午 10:40:29
表单 - OnActivated:8/14/2010 上午 10:40:29
表单 - 显示:8/ 14/2010 10:40:29 AM
表格 - OnPaint : 8/14/2010 10:40:29 AM
表格 - 无效:8/14/2010 10:40:29 AM
表格 - OnPaint : 8/14/2010 10: 40:29 上午
回答by Ahmed Said
The Shownevent occurs after the Loadevent. The main difference is not in the visibilityof the form but in its state(width, height, etc.).
该Shown事件发生后,Load事件。主要区别不在于表单的可见性,而在于其状态(宽度、高度等)。
To clarify, here is an example. Consider a form that has a default size of 100, 200and a WindowStatethat is Maximized. In the Loadevent handler, the size will be 100, 200. But in the Shownevent handler, the size will be your screen size.
为了澄清,这里有一个例子。考虑一个默认大小为100, 200且 aWindowState为的表单Maximized。在Load事件处理程序中,大小将为100, 200。但在Shown事件处理程序中,大小将是您的屏幕大小。
回答by Miral
Ok, I think I've worked out what's really going on now, and where my confusion was coming from (although not whyit behaves that way). It looks like the Shown event actually occurs insidethe Load event.
好的,我想我已经弄清楚现在到底发生了什么,以及我的困惑来自哪里(尽管不是为什么会这样)。看起来 Shown 事件实际上发生在Load 事件中。
Given this code:
鉴于此代码:
protected override OnLoad(EventArgs e)
{
MessageBox.Show("Enter Load");
base.OnLoad(e);
MessageBox.Show("Exit Load");
}
protected override OnShown(EventArgs e)
{
MessageBox.Show("Enter Shown");
base.OnShown(e);
MessageBox.Show("Exit Shown");
}
then the messages are shown in this order:
然后消息按以下顺序显示:
- Enter Load
- Enter Shown
- Exit Shown
- Exit Load
- 输入负载
- 输入显示
- 退出显示
- 出口负载
The Visible property is True in all four cases yet in noneof these cases is the form actually visible on screen (painted).
Visible属性是四个案件都还没有真正在没有这些案件的形式在屏幕上实际可见(画)。
The really weird thing though is that if I comment out the "Exit Load" messagebox then the form doesappear on screen beforethe "Enter Shown" message appears. It seems to be code executed after the base OnLoad call that it's really objecting to somehow.
但真正奇怪的是,如果我注释掉“出口装载”消息框,那么这个表单并在屏幕上出现之前的“输入显示”的消息。它似乎是在基础 OnLoad 调用之后执行的代码,它确实以某种方式反对。
回答by Fredou
one thing I know for sure is the shown event is executed after everything on the InitializeComponent is done and the form is showing up and it's in the shown that you should put the code that move object on the form based on the location of other object
我确定的一件事是在 InitializeComponent 上的所有内容都完成并且表单显示之后执行显示的事件,并且在显示中您应该根据其他对象的位置将移动对象的代码放在表单上
do a quick test with an empty project:
用一个空项目做一个快速测试:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MsgBox("load") 'form is still visible = false
End Sub
Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
MsgBox("shown") ' form is now visible = true
End Sub
End Class
回答by Cyril Gupta
I just checked and load fires before Shown as it should.
我只是在显示之前检查并加载了火灾。
There's obviously something wrong in your approach.
你的方法显然有问题。

