Почему копия значения MainForm создается, когда метод вызывается или вызывается в кросс-потоке?
Обновление: я думаю, что это как-то связано с ленивым созданием дескриптора окна для MainForm - но покаЯ не мог понять, как это приведет к поведению, замеченному здесь.
Приложение запрашивает данные через сторонний интерфейс COM, обеспечивая обратный вызов для обработки результатов. В обратном вызове пользовательский интерфейс должен быть обновлен - но обновление нет работает как положено. Это'как если бы была создана копия значения MainForm, когдаMainForm.DataReady
вызывается или вызывается напрямую через поток, но обновление пользовательского интерфейса работает, как ожидается, при выполнении из обработчика событий. Вы можете объяснить, почему?
(Заметка:AppDomain.CurrentDomain.Id
всегда1
проверено ли в MainForm или в ClassB.)
Исходный код - вызвать DataReady из экземпляра ClassB без логики InvokeRequred / Delegate / Invoke в MainForm. Изменение пользовательского интерфейса приложения работает, как и ожидалось, MainFormSomeListControl.EmptyListMsg = "Not Available"
изменение непридерживаться' (как будто применяется к отдельной копии MainForm)
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
Добавлена логика InvokeRequred для DataReady, которая по-прежнему вызывается непосредственно из ClassB, InvokeRequired никогда не соответствует действительности, изменение пользовательского интерфейса приложения работает, как и ожидалось, MainFormSomeListControl.EmptyListMsg = "Not Available"
изменение непридерживаться' (как будто применяется к отдельной копии MainForm)
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
ВызванныйMainForm.DataReady
прямо из ClassB Получил исключение: "Invoke или BeginInvoke нельзя вызывать для элемента управления, пока не будет создан дескриптор окна. " пока я не заставил создание дескриптора окна. Затем это'такое же поведение, как и раньше, а именно, InvokeRequired никогда не выполняется, изменение пользовательского интерфейса приложения работает, как и ожидалось, MainFormSomeListControl.EmptyListMsg = "Not Available"
изменение непридерживаться' (как будто применяется к отдельной копии MainForm)
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
Выполнено из обработчика событий Определено обычай »получил данные события в ClassA и ClassB. ClassA прослушивает ClassB.got_data_event и вызывает ClassA.got_data_event, MainForm прослушивает ClassA.got_data_event и обрабатывает его, вызывая DataReady (). Это работает - InvokeRequired имеет значение true, Invoke оправдан, интерфейс приложения и интерфейс MainForm работают должным образом.
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