Загрузка и показ событий в Windows Forms - PullRequest
24 голосов
/ 29 декабря 2008

Надеюсь, я просто упускаю что-то очевидное, но я пытаюсь разобраться в различиях между событиями Load и Shown в Windows Forms .

Традиционно я использовал только Load (или фактически OnLoad, поскольку я думаю, что переопределить метод более чисто, чем полагаться на конструктор, чтобы подключить событие к себе), поскольку он доступен во всех версиях .NET. , В .NET 2.0 было представлено событие Shown.

Теперь, если вы посмотрите на их описания в документации MSDN («Загрузка: Происходит до того, как форма отображается в первый раз.», «Показано: Происходит при первом отображении формы.») It звучит как должно произойти событие Load, затем форма должна стать видимой, затем должно произойти событие Shown; комбинация этих двух тем позволяет вам выполнять некоторые задачи как до, так и после отображения формы. Имеет смысл, верно?

Однако эксперимент показал, что событие Shown неизменно наступает за до события Load, всякий раз, когда я его пробую (и оба происходят до того, как форма становится видимой). И все же, когда я гуглюсь, когда обнаруживаю страницу, которая говорит о порядке запуска этих событий, они всегда перечисляют событие Load, которое запускается первым.

Я просто схожу с ума, или я что-то пропустил? (И если они происходят примерно в одно и то же время, то почему было добавлено событие Shown?)

(Мое текущее решение сделать что-то как до, так и после показа формы - это использовать OnLoad для «до показа» и запускать кратковременный таймер однократного действия для «после показа». надежно, но это немного уродливо, и я надеялся, что было более чистое решение. Но, похоже, событие Shown не так.)

Ответы [ 6 ]

53 голосов
/ 29 декабря 2008

Избегайте использования MessageBox.Show () для отладки. Он прокачивает цикл сообщений, нарушая нормальный поток событий. Событие Load вызывается Windows, отправляющей сообщение WM_SHOWWINDOW, непосредственно перед тем, как окно становится видимым. Нет уведомления Windows о том, что «ваше окно теперь полностью отображается», поэтому разработчики WF придумали хитрость для генерации события Shown . Они используют Control.BeginInvoke (), гарантируя, что метод OnShown () будет вызван, как только программа снова выйдет из режима ожидания и снова войдет в цикл обработки сообщений.

Этот трюк имеет множество других применений, особенно когда вам нужно отложить выполнение кода, начатого событием. Однако в вашем случае он разваливается, потому что вы используете MessageBox.Show (). Его цикл обработки сообщений отправляет делегата, зарегистрированного в BeginInvoke (), в результате чего событие Shown запускается до , когда отображается окно.

Существует множество других способов получить диагностику помимо MessageBox. Debug.Print () и Console.WriteLine () удобны, их вывод поступает в Окно вывода Visual Studio , не оказывая вредного влияния на обычную последовательность запуска событий. Простой точка останова тоже может творить чудеса.

14 голосов
/ 14 августа 2010

Вот последовательность событий, которые я проследил. Пусть это поможет другим решить, как они хотели бы позвонить, или настроить свою собственную обработку событий

Отслеженные события

Форма - размер клиента изменен: 14.08.2010 10:40:28
Форма - добавлен элемент управления - button1: 14.08.2010 10:40:29
Форма - Конструктор: 14.08.2010 10:40:29
Форма - Ручка Создано: 14.08.2010 10:40:29
Форма - недействительна: 14.08.2010 10:40:29
Форма - Событие загрузки формы: 14.08.2010 10:40:29
Форма - Загружен: 14.08.2010 10:40:29
Форма - Создать элемент управления: 14.08.2010 10:40:29
Форма - Вкл. Активировано: 14.08.2010 10:40:29
Форма - Показано: 14.08.2010 10:40:29
Форма - OnPaint: 14.08.2010 10:40:29
Форма - недействительна: 14.08.2010 10:40:29
Форма - OnPaint: 14.08.2010 10:40:29

4 голосов
/ 29 декабря 2008

Событие Shown наступает после события Load. Основное отличие заключается не в видимости формы, а в ее состоянии (ширина, высота и т. Д.).

Чтобы уточнить, вот пример. Рассмотрим форму с размером по умолчанию 100, 200 и WindowState, равным Maximized. В обработчике Load размер будет 100, 200. Но в обработчике событий Shown размер будет размером экрана .

2 голосов
/ 29 декабря 2008

Хорошо, я думаю, что я понял, что на самом деле происходит сейчас, и откуда возникло мое замешательство (хотя не , почему так себя ведет). Похоже, что событие 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");
}

тогда сообщения показываются в следующем порядке:

  1. Ввод нагрузки
  2. Введите Показано
  3. Показан выход
  4. Выходная нагрузка

Свойство Visible имеет значение True во всех четырех случаях, но в нет из этих случаев является формой, фактически видимой на экране (закрашена).

Действительно странная вещь заключается в том, что если я закомментирую окно сообщения «Exit Load», то на экране появляется до - появляется сообщение «Enter Shown» Кажется, это код, выполняемый после базового вызова OnLoad, на который он как-то возражает.

1 голос
/ 29 декабря 2008

я точно знаю, что показанное событие выполняется после того, как все в 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
0 голосов
/ 29 декабря 2008

Я только что проверил и загрузил пожары, прежде чем показано, как следует.

В вашем подходе явно что-то не так.

...