Загрузка и отображение событий в Windows Forms
Надеюсь, я просто пропустил что-то очевидное, но я пытаюсь разобраться в различиях между событиями Load и Show в Windows Forms.
Традиционно я использовал Load (или фактически OnLoad, так как я считаю, что более чистое переопределение метода, чем полагаться на конструктор, чтобы подключить событие к себе), поскольку он доступен во всех версиях .NET., С .NET 2.0 было представлено событие Shown.
Теперь, если вы посмотрите описания для них в документации MSDN ( "Загрузить: Происходит до того, как форма отображается в первый раз"., "Показывается: Происходит всякий раз, когда форма впервые отображается".) это звучит как должно происходить событие Load, тогда форма должна стать видимой, тогда должно произойти событие Shown; комбинация двух, что позволяет выполнять некоторые задачи как до, так и после формы. Имеет смысл, правильно?
Однако эксперимент показал, что событие Shown неизменно встречается перед событием Load, всякий раз, когда я его пытаюсь (и оба возникают до того, как форма становится видимой). И все же, когда я google вокруг всякий раз, когда я обнаруживаю страницу, в которой говорится о порядке, в котором эти события запущены, они всегда перечисляют начальное событие Load.
Я просто схожу с ума, или я что-то пропустил? (И если они происходят примерно в одно и то же время, то почему было добавлено событие Shown?)
(Мое текущее решение для того, чтобы что-то делать до и после показа формы, - использовать OnLoad для "до показа" и запускать таймер с одним выстрелом для "после показа", который работает нормально и надежно, но это немного уродливо, и я надеялся, что есть более чистое решение. Но похоже, что событие Shown не так.)
Ответы
Ответ 1
Избегайте использования MessageBox.Show() для его отладки. Он накачивает контур сообщения, нарушая нормальный поток событий. Событие Load запускается Windows, отправляя сообщение WM_SHOWWINDOW, перед тем, как окно станет видимым. Нет уведомления Windows о том, что "ваше окно теперь полностью показано", поэтому дизайнеры WF придумали трюк для создания события Shown. Они используют Control.BeginInvoke(), гарантируя, что метод OnShown() вызывается, как только программа снова простаивает и повторно входит в цикл сообщения.
Этот трюк имеет множество других применений, особенно когда вам приходится задерживать выполнение кода, запускаемого событием. Однако в вашем случае он разваливается, потому что вы используете MessageBox.Show(). Его цикл сообщений отправляет делегат, зарегистрированный в BeginInvoke(), заставляя событие Shown запускаться до того, как будет показано окно.
Существует множество других способов получить диагностику помимо MessageBox. Debug.Print() и Console.WriteLine() удобны, их вывод идет в Окно вывода Visual Studio без каких-либо негативных последствий для нормального последовательность срабатывания событий. Простая точка может творить чудеса.
Ответ 2
Здесь последовательность отслеживаемых событий. Пусть это поможет другим решить, как они хотели бы позвонить или настроить обработку пользовательских событий.
Прослеживаемые события
Форма - Изменен размер клиента: 8/14/2010 10:40:28 AM
Form - Control Added - button1: 8/14/2010 10:40:29 AM
Форма - конструктор: 8/14/2010 10:40:29 AM
Form - Handle Создано: 8/14/2010 10:40:29 AM
Форма - недействительна: 8/14/2010 10:40:29 AM
Форма - Форма Загрузка: 8/14/2010 10:40:29 AM
Форма - загружена: 14.08.2010 10:40:29
Форма - Создать контроль: 8/14/2010 10:40:29 AM
Форма - OnActivated: 8/14/2010 10:40:29 AM
Форма - показано: 14.08.2010 10:40:29
Форма - OnPaint: 8/14/2010 10:40:29 AM
Форма - недействительна: 8/14/2010 10:40:29 AM
Форма - OnPaint: 8/14/2010 10:40:29 AM
Ответ 3
Событие Shown
происходит после события Load
. Основное различие заключается не в видимости формы, а в ее состоянии (ширина, высота и т.д.).
Чтобы пояснить, вот пример. Рассмотрим форму, которая имеет размер по умолчанию 100, 200
и WindowState
, который равен Maximized
. В обработчике событий Load
размер будет 100, 200
. Но в обработчике событий Shown
размер будет размером вашего экрана.
Ответ 4
Хорошо, я думаю, что я разработал то, что действительно происходит сейчас, и откуда возникла моя путаница (хотя и не потому, что так ведет себя). Похоже, что событие Shown на самом деле происходит внутри события Load.
С учетом этого кода:
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");
}
тогда сообщения отображаются в следующем порядке:
- Введите Load
- Введите отображаемый
- Exit Show
- Exit Load
Свойство Visible является True во всех четырех случаях, но ни в одном из этих случаев форма, видимая на экране (покрашена).
Действительно странно, что если я прокомментирую сообщение "Выход из загрузки", то форма появится на экране до появится сообщение "Enter Shown". Кажется, что код был выполнен после вызова базовой OnLoad, что он действительно возражает против.
Ответ 5
одна вещь, которую я точно знаю, показывает, что указанное событие выполняется после того, как все на InitializeComponent сделано, и форма отображается, и в показанном вами примере вы должны поместить код, который перемещает объект по форме, на основе местоположения другой объект
выполните быстрый тест с пустым проектом:
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
Ответ 6
Я только что проверил и загрузил огни перед тем, как это показано.
В вашем подходе явно что-то не так.