Закрытие формы из другого потока происходит слишком рано, вызывая исключение - PullRequest
0 голосов
/ 13 августа 2010

У меня следующая ситуация,

Private Sub MyButton_Click(sender as Object, args as EventArgs) Handles MyButton.Click
    Me.pleaseWaitFrm = New PleaseWaitForm()
    ' Fire up new thread to do some work in (AddressOf DoMyWork)
    Me.pleaseWaitFrm.ShowDialog()
End Sub

Private Sub DoMyWork()
   Dim log = Me.DoTheActualWork()

   Me.pleaseWaitFrm.Close()

   Using logFrm as New LogViewer(log)
       logFrm.ShowDialog()
   End Using
End Sub

Если вызов DoTheActualWork() завершается достаточно быстро, вызов Me.pleaseWaitFrm.Close() происходит во время вызова Me.pleaseWaitFrm.ShowDialog(). Результат, что неудивительно, это исключение:

Произошло необработанное исключение типа «System.InvalidOperationException» в System.Windows.Forms.dll

Дополнительная информация: Значение Close () не может быть вызвано при выполнении CreateHandle ().

Очевидно, что это старая проблема «Вы не можете. Закрыть () WinForm, пока она находится в процессе загрузки». Но что для меня не очевидно, как лучше всего предотвратить это в этом случае? Как безопасно и надежно отложить .Close (), пока это не будет безопасно в этой ситуации?

Ответы [ 2 ]

2 голосов
/ 13 августа 2010

Me.pleaseWaitFrm.Close ()

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

Это исключение, которое вы получаете, является явным побочным эффектом этого.Вы должны использовать Control.Invoke (), чтобы закрыть диалог.Это автоматически решает вашу проблему, цель делегата не может быть выполнена до тех пор, пока не будет загружено диалоговое окно.

Использование класса BackgroundWorker, это делает это легко.Вы можете закрыть диалоговое окно в обработчике событий RunWorkerCompleted.

1 голос
/ 13 августа 2010

Почему бы не установить флажок "ShouldClose", который можно проверить, когда безопасно закрыть форму - и закрыть ее, если требуется?

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

    ''in PleaseWaitForm:
    Public Property ShouldClose as boolean = false

Private Sub frmSplash_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Me.Close()
End Sub

    ''Your posted code
    Private Sub MyButton_Click(sender as Object, args as EventArgs) Handles MyButton.Click
        Me.pleaseWaitFrm = New PleaseWaitForm()
        '' Fire up new thread to do some work in (AddressOf DoMyWork)
        Me.pleaseWaitFrm.ShowDialog()
    End Sub

    Private Sub DoMyWork()
       Dim log = Me.DoTheActualWork()


       Me.pleaseWaitFrm.ShouldClose = True
       If Me.pleaseWaitFrm.Created Then
           Me.pleaseWaitFrm.Created.Close
       End If

       Using logFrm as New LogViewer(log)
           logFrm.ShowDialog()
       End Using
    End Sub

Короче говоря, если мы можем закрыть форму, мы делаем - иначе, установите флаг, и форма будет делатькогда загрузка заканчиваетсяна frmSplash, который проверяет значение, а не использует событие Load

Редактировать: Обнаружен и исправлен баг

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