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