2016-08-16 6 views
0

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

Вот сломанный код, я заметил вокруг линий, сломанных объяснить

Private Sub RunBtn_Click(sender As Object, e As EventArgs) Handles RunBtn.Click 
    Dim transferThread As New System.Threading.Thread(AddressOf RunTransfer) 
    StartContinuousProg() 
    UpdateStatus("Running Transfer...") 
    StartTime = Date.Now 

    incrementProgMethod = New incrementProgDelegate(AddressOf incrementProg) 
    finishProgMethod = New finishProgDelegate(AddressOf finishProg) 
    updateStatusMethod = New updateStatusDelegate(AddressOf UpdateStatus) 
    writeErrorMethod = New writeErrorDelegate(AddressOf WriteError) 
    writeWarningMethod = New writeWarningDelegate(AddressOf WriteWarning) 
    writeAlertMethod = New writeAlertDelegate(AddressOf WriteAlert) 
    EndTransferMethod = New EndTransferDelegate(AddressOf endTransfer) 

    transferThread.Start() 

End Sub 

Private Sub RunTransfer() 

    '(...Some work...) 


    For catRow = 0 To CATImportArr.Length - 1 
     Dim currentCATSerial, currentCATAsset As String 
     currentCATSerial = LCase(CATImportArr(catRow).getSerialNumber) 
     currentCATAsset = LCase(CATImportArr(catRow).getAssetNumber) 

'This line produces this error: Unable to cast object of type 'System.String' to type 'System.Delegate'. 
     Invoke(updateStatusMethod("Searching " & currentCATSerial & ", " & currentCATAsset & "...")) 

'This line doesn't crash but the UI label doesn't change 
     updateStatusMethod.Invoke("Searching " & currentCATSerial & ", " & currentCATAsset & "...") 

'This line doesn't crash but the UI progress bar doesn't change 
     Invoke(finishProgMethod) 

Эти методы вызываются посредством делегатов

Public Function UpdateStatus(ByRef text As String) 
    ParentForm.StatusLbl.Text = text 
    Return text 
End Function 

Public Sub finishProg() 
    ParentForm.StatusProg.Value = 100 
End Sub 

ответ

1

Delegate просто класс держа ссылку на метод. Вы не можете передать параметры самому Delegate.

Для передачи параметров методы вы хотите вызвать, вы должны использовать Control.Invoke(Delegate, Object()) перегрузки, когда вы передаете параметр (ы) к методу Invoke(), после того, как вы указали делегат:

Invoke(updateStatusMethod, "Searching " & currentCATSerial & ", " & currentCATAsset & "...") 

Поскольку второй параметр Control.Invoke(Delegate, Object()) объявлен ParamArray вы можете держать на задании параметров, если вам нужно, просто разделив их запятой:

Invoke(updateStatusMethod, [param1], [param2], [param3], ...) 
+0

Или. Begininvoke (sub() do main thread work end sub) – ThatGuy

+0

@ImStartingToHateThisSite: Если он не хочет/нуждается в 'BeginInvoke()', тогда лучше не использовать его. 'Begin ***' _usually_ требует вызова 'End ***', и хотя команда WinForms заявила, что это безопасно, даже не делая этого (это относится только к элементам управления), я все равно не буду доверять ему 100 %. Кроме того, если он использует .NET 3.5 или ниже, он не может использовать лямбда-выражения ('Sub()'). –

+0

Интересные моменты. Я предлагаю это только потому, что это простота использования и чистоты в редакторе. Рад, что вы ответили; Я не знал о потенциальных проблемах с использованием этого. Мне нужно немного почитать об этом. Есть так много функций с .net, я никогда не смогу читать их все ... – ThatGuy

Смежные вопросы