Dlaczego kopia wartości MainForm jest tworzona, gdy metoda jest wywoływana lub wywoływana jest wątek krzyżowy?

Aktualizacja: Myślę, że ma to coś wspólnego z leniwym tworzeniem instancji okna dla MainForm - ale nie udało mi się ustalić, w jaki sposób spowoduje to zachowanie widoczne tutaj.

Aplikacja żąda danych za pośrednictwem interfejsu COM innej firmy, zapewniając wywołanie zwrotne w celu przetworzenia wyników. W wywołaniu zwrotnym interfejs użytkownika musi zostać zaktualizowany - ale aktualizacja nie działa zgodnie z oczekiwaniami. To tak, jakby kopia wartości MainForm została utworzona, kiedyMainForm.DataReady jest wywoływany lub wywoływany bezpośrednio przez wątek krzyżowy, ale aktualizacja interfejsu użytkownika działa zgodnie z oczekiwaniami, gdy jest wykonywana z modułu obsługi zdarzeń. Czy możesz mi wytłumaczyć dlaczego?

(Uwaga:AppDomain.CurrentDomain.Id jest zawsze1 czy zbadane w MainForm lub w ClassB.)

Kod początkowy - wywołanie DataReady z instancji ClassB bez logiki InvokeRequred / Delegate / Invoke w MainForm. Zmiana interfejsu aplikacji działa zgodnie z oczekiwaniami, MainFormSomeListControl.EmptyListMsg = "Not Available" zmiana nie „przykleja się” (jak w przypadku zastosowania do oddzielnej kopii formularza głównego)



Module AppGlobals
  Public WithEvents A As ClassA
End Module

Partial Friend Class MyApplication
  Private Sub MyApplication_Startup(ByVal sender As Object,
                                          ByVal e As StartupEventArgs) Handles Me.Startup
    A = New ClassA()

  End Sub
End Class

Class MainForm

  private sub getData
    ToggleWait(True)
    SomeListControl.Clear()
    A.getData() 'Sets up the com object & callback
  end sub

  Public Sub DataReady()
    ToggleWait(False)
    ' Do something with the data
  End Sub

  Private Sub ToggleWait(toggle as Boolean)
    Application.UseWaitCursor = False
    if toggle then
      SomeListControl.EmptyListMsg = "Not Available"
    else
      SomeListControl.EmptyListMsg = "Please Wait"
    end if
  End Sub

End Class

Class ClassA

  public sub getData()
     Dim ComObj as New ComObject
     Call ComObj.setClient(New ClassB)
  End Sub

End Class

Class ClassB
  Implements IComObjectClient

  sub getdata_callback(results() as Object) handles IComObjectClient.getdata_callback
    ' Get the results
    MainForm.DataReady() 
  end sub

End Class

Dodano logikę InvokeRequred do DataReady, nadal wywoływaną bezpośrednio z ClassB. InvokeRequired nigdy nie jest prawdziwe, zmiana interfejsu użytkownika aplikacji działa zgodnie z oczekiwaniami, MainFormSomeListControl.EmptyListMsg = "Not Available" zmiana nie „przykleja się” (jak w przypadku zastosowania do oddzielnej kopii formularza głównego)


  Class MainForm
    Public Delegate Sub DataReadyDelegate(ByVal toggle As Boolean)
    ...
    Public Sub DataReady()
        If InvokeRequired Then
            Invoke(New DataReadyDelegate()
        Else
          ToggleWait(False)
          ' Do something with the data
        End If
    End Sub
    ...
  End Class

PrzywołanyMainForm.DataReady bezpośrednio z ClassB Masz wyjątek: „Wywołanie lub BeginInvoke nie może zostać wywołane na kontrolce, dopóki nie zostanie utworzony uchwyt okna”. dopóki nie zmusiłem do stworzenia klamki. Wtedy jest to takie samo zachowanie jak wcześniej, mianowicie InvokeRequired nigdy nie jest prawdziwe, zmiana interfejsu użytkownika aplikacji działa zgodnie z oczekiwaniami, MainFormSomeListControl.EmptyListMsg = "Not Available" zmiana nie „przykleja się” (jak w przypadku zastosowania do oddzielnej kopii formularza głównego)


Class ClassB
  Implements IComObjectClient
  Public Delegate Sub DataReadDelegate()

  sub getdata_callback(results() as Object) handles IComObjectClient.getdata_callback
    ' Get the results 
    If Not MainForm.IsHandleCreated Then
      ' This call forces creation of the control's handle
      Dim handle As IntPtr = MainForm.Handle
    End If
    MainForm.Invoke(New DataReadyDelegate(AddressOf MainForm.DataReady))
  end sub

End Class

Wykonane z obsługi zdarzeń Zdefiniowane niestandardowe zdarzenia „dostań dane” w ClassA i ClassB. ClassA nasłuchuje ClassB.got_data_event i podnosi ClassA.got_data_event, MainForm nasłuchuje ClassA.got_data_event i obsługuje go wywołując DataReady (). To działa - InvokeRequired jest prawdą, Invoke jest wymuszone, zmiany interfejsu aplikacji i interfejsu użytkownika MainForm działają zgodnie z przeznaczeniem.


  Class MainForm
    Public Delegate Sub DataReadyDelegate()
    ...
    Public Sub DataReady()
        If InvokeRequired Then
            Invoke(New DataReadyDelegate()
        Else
          ToggleWait(False)
          ' Do something with the data
        End If
    End Sub

    Public Sub _GotData_HandleEvent(ByVal resultMessage As String)
        DataReady()
    End Sub

    Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles Me.Load
        ...
        ToggleWait(False)
        AddHandler A.GotData, AddressOf _GotData_HandleEvent
        ...
    End Sub
    ...
  End Class

questionAnswers(1)

yourAnswerToTheQuestion