Windows 窗体应用程序中事件的真实顺序是什么?
我的意思是,当我将代码放入Form_Shown事件中时,我希望代码仅在表单显示后运行:
动词(与宾语一起使用),显示,显示或显示,显示。1. 导致或允许被看到... - http://dictionary.reference.com/browse/shown
但这个Form_Shown事件有点误导。如果我这样做,事件中一些沉重的东西,却仿佛代码被执行之前的Form已完成被证实。假设我在一个表单上有一个MainMenu、一个小Toolbar和一个TextBox。
我想做一些繁重的事情(暂时不要考虑线程和工人......),所以我可以使用的最后一个事件我认为是Form_Shown. 所以我把我的重代码放在那里,但是当表单开始显示时,我最终等待了大约 5 - 6 秒的时间Toolbar来显示和内容(这最终发生在我的重代码完成它的事情之后。
这让我相信我订阅了错误的事件。我根本不想要这个Form_Shown事件。我真正需要的是:
Form_WhenALLTheThingsHaveShownEventHandler 事件。
那么,我怎么知道_什么时候所有的东西(控件)都已经完全加载并显示出来了?
该Shown事件实际上是与引发的初始化相关的最后一个事件。但是,请注意,Windows(以及其他平台)中 UI 对象的实际渲染(在屏幕上绘制)是延迟的。UI 对象的创建仅分配所有必要的资源并使该对象的可视区域“无效”。然后,平台稍后安排渲染事件(在非托管 Windows 中,这是WM_PAINT,在 Winforms API 中,这将是Paint实例的事件Control)。
在 UI 对象的线程可用之前,无法分派渲染事件,并且如果事件中有长时间运行的代码Shown,则这将使 UI 对象的线程在代码持续时间内不可用。也就是说,在代码完成之前不会绘制任何内容。
您还可以使用其他事件来更可靠地检测事情何时“稳定下来”。例如,该Application.Idle事件告诉您主应用程序线程何时即将进入空闲状态。或者,您可以只订阅表单的Paint事件。在任何一种情况下,您都希望使用它BeginInvoke()来分派长时间运行的代码,这样就不会阻止这些事件的处理。
现在,综上所述:您确实不应该在 UI 线程中执行任何长时间运行的工作。使用上述任一事件并不能解决根本问题;它只是将问题延迟到 UI 初始渲染之后。当你的长时间运行的工作正在执行时,UI 仍然会保持阻塞状态,坦率地说,用户实际上可能会发现根本没有 UI 比有一些看起来可以交互但他们可以交互的东西更好。 't(即对他们的输入没有响应)。
在最新版本的 .NET 中,有一些非常好的机制可用于将长时间运行的工作转移到后台线程,以便 UI 可以保持响应。请参阅C# 中的Taskand关键字async。await如果您愿意,也可以使用较旧的BackgroundWorker对象来完成相同的任务。