【问题标题】:Using Events to update UI from a backgroundworker with another class使用事件从具有另一个类的后台工作人员更新 UI
【发布时间】:2015-04-07 01:46:41
【问题描述】:

我正在尝试使用事件来更新来自不同类的后台工作人员的文本框。

这与this SO post 中提到的问题相同,只是我使用的是 VB.NET。我正在尝试实施@sa_ddam213 提出的第二个建议的解决方案。

我收到一条错误消息:“跨线程操作无效:控件 'txtResult' 从创建它的线程以外的线程访问。”

这是我的代码:

Public Class DataProcessor
    Public Delegate Sub ProgressUpdate(ByVal value As String)
    Public Event OnProgressUpdate As ProgressUpdate

    Private Sub PushStatusToUser(ByVal status As String)
        RaiseEvent OnProgressUpdate(status)
    End Sub

    Public Sub ProcessAllFiles(ByVal userData As UserData)
        'Do the work
    End Sub
End Class

Public Class MainForm
    Private bw As New BackgroundWorker
    Private dp As New DataProcessor

    Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)

        If bw.CancellationPending = True Then
            e.Cancel = True
        Else
            dp.ProcessAllFiles(CType(e.Argument, UserData))
        End If
    End Sub

    Private Sub dp_OnProgressUpdate(ByVal status As String)
        txtResult.Text = status
    End Sub

    Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        bw.WorkerReportsProgress = True
        bw.WorkerSupportsCancellation = True
        AddHandler bw.DoWork, AddressOf bw_DoWork
        AddHandler bw.ProgressChanged, AddressOf bw_ProgressChanged
        AddHandler bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted

        AddHandler dp.OnProgressUpdate, AddressOf dp_OnProgressUpdate
    End Sub
End Class

谢谢大家!

【问题讨论】:

  • 您有一个从表单内部在 BGW 上运行的类。如果 DP 类创建并运行 BGW,它可以捕获进度报告和已完成事件并将它们简单地报告给表单,而不是尝试从底部到顶部一直冒泡信息。

标签: vb.net multithreading class backgroundworker


【解决方案1】:

事件仍然来自与 UI 不同的线程。您需要将唤醒后委托给 UI。我不检查InvokeRequired,因为我知道它来自工作线程。

Me 是表单,Invoke 请求将处理将数据带到 UI 线程的工作的委托。这里我的 Delegate Sub 是一个 lambda Sub,而不是使用普通的 Sub 例程 - 更简单的设计。

Private Sub dp_OnProgressUpdate(ByVal status As String)
   'invoke the UI thread to access the control
   'this is a lambda sub
   Me.Invoke(Sub
               'safe to access the form or controls in here
               txtResult.Text = status
             End Sub)
 End Sub

【讨论】:

  • 这行得通,谢谢。额外的功劳,你能进一步解释一下吗?
【解决方案2】:

也许你可以尝试做这样的事情?

    Private Delegate Sub del_Update(ByVal status As String)

    Private Sub dp_OnProgressUpdate(ByVal status As String)
        If txtResult.InvokeRequired Then
            txtResult.Invoke(New del_Update(AddressOf dp_OnProgressUpdate),  New Object() {status})
        Else
            target_textbox.text = status 
        End If

    End Sub

【讨论】:

  • 是的,这是旧的委托方式。更多的代码来做同样的事情 - 你不觉得吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多