Закрытие формы из обработчика загрузки - PullRequest
8 голосов
/ 08 апреля 2009

У меня очень странное поведение, которое, кажется, происходит только в одной форме.

В основном я создаю экземпляр Form и вызываю Show(), чтобы отобразить неблокирующую форму. В обработчике событий Load этой формы у меня есть логика, которая может вызывать this.Close() при определенных обстоятельствах. Это закрывает форму, но затем метод Show() в коде клиента выдает ObjectDisposedException.

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

в System.Windows.Forms.Control.CreateHandle ()
в System.Windows.Forms.Form.CreateHandle ()
в System.Windows.Forms.Control.get_Handle ()
в System.Windows.Forms.ContainerControl.FocusActiveControlInternal ()
в System.Windows.Forms.Form.SetVisibleCore (логическое значение)
в System.Windows.Forms.Control.Show ()
... и т.д.

Вот что я вижу:

  1. Control.Show() называется
  2. моя форма запущена
  3. метод OnFormLoad называется
  4. вызывается обработчик события FormLoad, внутри которого я вызываю this.Close()
  5. метод OnFormClosing называется
  6. обработчик события FormClosing называется
  7. Dispose вызывается в моей форме и все его пользовательские элементы управления

и затем где-то ближе к концу Control.Show() метода, он пытается получить дескриптор формы, который приходит в ужас и выдает исключение, потому что объект помечен как удаленный.

Мой реальный вопрос: почему я могу делать это точно так же в любой другой форме, которая у меня есть, без исключений? Это проблема GC? Я попытался сделать GC.Collect() вызов сразу после this.Close(), и это не имеет значения. Как я уже сказал, это происходит в этой форме 100% времени, и нигде больше, независимо от дочерних пользовательских элементов управления, области видимости переменной формы и т. Д.

Есть идеи?

Ответы [ 11 ]

25 голосов
/ 22 июля 2013

Лучший способ сделать это:

 this.BeginInvoke(new MethodInvoker(this.Close));

это самый простой способ получить ObjectDisposedException

8 голосов
/ 29 октября 2011

Я знаю, что это старая проблема, но никто, похоже, не опубликовал ответ obvoius.

Вы говорите, что звоните Control.Show(), а затем Form.Close(), а затем форма Утилизируется. Ну, если только вы не используете MDI или не используете ShowDialog, это так же задокументировано. Хотя краткая версия документации Close() «Закрывает форму», на самом деле она также неявно утилизируется при определенных условиях.

См. Раздел замечаний: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.close.aspx

Если вы хотите снова показать форму. Используйте метод Hide() вместо Close().

Надежда, которая помогает другим ищущим душам.

И, ребята, не переставайте искать "Я не знаю, почему это иногда работает". Это становится программным обеспечением с ошибками с большим количеством защитных «я назову этот метод снова на всякий случай». Не хорошо.

6 голосов
/ 08 апреля 2009

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

В моей форме я переопределяю методы OnFormLoad и OnFormClose, где я сохраняю / восстанавливаю размер, расположение и WindowState формы в / из реестра. Я взял этот код, и он решил проблему. Странная вещь, я отложил это, и проблема не вернулась.

Я наконец воспроизвел проблему: вы должны полностью открыть форму, развернуть ее, а затем закрыть, чтобы состояние «Развернуто» было сохранено в реестре. Затем, когда вы снова откроете его, он установит его на Maximized, и если он закрывается в обработчике загрузки, он пытается получить доступ к размеру / расположению при закрытии. Видимый доступ к этим значениям в методе OnFormClosing заставляет форму пытаться сфокусироваться, ЕСЛИ И ТОЛЬКО ЕСЛИ форма развернута, что недопустимо, так как форма была удалена.

Таким образом, по сути, вы не можете получить доступ к свойствам отображения формы в методе OnFormClosing формы, если эта форма будет вызывать Close из своего события Load (если только вы сначала не проверили опору Disposed)

довольно специфическая часть мудрости Винформ, которую я знаю, но я все равно записываю ее.

4 голосов
/ 30 октября 2013

Если вы хотите закрыть форму, как если бы пользователь нажал крестик в верхнем правом углу (обычно это означает отмена), просто добавьте следующий код.

this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.Close();

Это также работает в функции загрузки формы:

private void MyForm_Load (object sender, EventArgs e)
{
    // do some initializations

    if (!ContinueLoadingForm())
    {
         this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
         this.Close();
         return;
    }
    // continue loading the form
}

Если вы не хотите, чтобы форма была видна в течение короткого времени, установите для свойства Visible значение false (например, в конструкторе или конструкторе) и установите для него значение true, если вы уверены, что программа может продолжить загрузку.

3 голосов
/ 08 апреля 2009

В случае загрузки не очень хорошая идея закрыть форму. Сделайте это после Активированного события.

1 голос
/ 08 апреля 2009

Одна возможность:

У них может быть таймер в этой форме, который инициализируется и включается в их событие FormLoad. Таймер также должен быть отключен и остановлен до закрытия формы, если таймер пытается получить доступ к форме при ее запуске.

Я видел формы, которые раньше это делали ...

0 голосов
/ 19 ноября 2015

Насколько я понимаю, установка DialogResult формы закроет форму - возможно, она должна отличаться от DialogResult.None. (то есть вам не нужно вызывать метод Form.Close ()).

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

Также может быть лучше, если, как было предложено, у вас есть собственность, например.

private bool _loadedOk = false; 

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

Возможно, кто-то может предложить лучшее событие, чтобы сделать это в ??

0 голосов
/ 11 февраля 2012

Form.Shown () Трюк тоже.

0 голосов
/ 09 апреля 2009

Хорошо, оказывается, это немного проще и более обобщенно, чем я думал, но все же странно и неясно.

Если вы сохраняете / загружаете форму Size / Location / WindowState, когда форма загружается / закрывается, как мы это делаем, вы должны сначала убедиться, что метод OnLoad вызывает base.OnLoad, чтобы обработчик события Form Load сработал, и ТО установить свойства. Невыполнение этого требования вызовет проблему, только если форма вызывает метод Close из метода Load. Вы получите ObjectDisposedException при вызове Show после завершения события закрытия формы.

У меня болит голова.

0 голосов
/ 08 апреля 2009

Вы пытались войти в код .net, чтобы увидеть, какая строка кода вызывается при возникновении исключения? Если у вас VS 2008, вы можете сделать это, перейдя в Сервис -> Параметры -> Отладка и выбрав Включить пошаговое выполнение .NET Framework. Имейте в виду, что загрузка всех необходимых файлов может занять некоторое время, но таким образом вы можете перейти в форму. Show () и точно увидеть, что происходит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...