另一个类中的UI更新和委托在单独的线程中不起作用

时间:2016-09-29 13:52:22

标签: vb.net multithreading user-interface scope

为了保持UI的响应能力,我使用一个单独的线程来执行各种过程,例如一些FTP下载。

Private Sub Button11_Click(sender As Object, e As EventArgs) Handles Button11.Click
    Dim ThreadResync As System.Threading.Thread
    ThreadResync = New System.Threading.Thread(AddressOf Bodacc_ResyncFTP)
    ThreadResync.Start()
End Sub

Sub Bodacc_ResyncFTP()
    Dim MyBodacc As bodacc_data = New bodacc_data
    MyBodacc.Label_Status = Form1.Label1
    MyBodacc.ResyncFTP()
End Sub

使用线程更新UI的方法是Delegate,所以在bodacc_data我必须

Public Class bodacc_data
    ......
    Delegate Sub UpdateLabelDelg(text As String, ThisLabel As Label)
    Public Delegate_label As UpdateLabelDelg = New UpdateLabelDelg(AddressOf set_label)
    Public Label_Status = Label
    ......
    Sub set_label(stext As String, ThisLabel As Label)
        ThisLabel.Text = stext
    End Sub
    .....

    Sub ResyncFTP()
        //says hello
        If Label_Status.InvokeRequired = True Then
            Label_Status.Invoke(Delegate_label, New Object() {"Working...", Label_Status})
        Else
            Label_Status.Text = "Working..."
        End If

        //do stuff
    End Sub
End Class

它就像一个魅力。但我有许多类或多或少相同(磁盘更新,数据库更新,FTP更新),并且必须复制/通过所有委托/外部标签声明/迷你子/调用声音愚蠢。

所以我创建了一个类来处理这些UI更新/委托,以便快速访问

Public Class Form_UI

    Delegate Sub UpdateLabelDelg(text As String, ThisLabel As Label)
    Public Delegate_label As UpdateLabelDelg = New UpdateLabelDelg(AddressOf set_label)

    Private Labels(2) As Label

    Sub New()

        Labels(0) = Form1.Label1
        Labels(1) = Form1.Label2
        Labels(2) = Form1.Label3

    End Sub

    Sub set_label(stext As String, ThisLabel As Label)
        ThisLabel.Text = stext
    End Sub


    Public Sub ChangeLabel(ByVal LabelNum As Integer, nText As String)
        LabelNum = LabelNum - 1

        If Labels(LabelNum).InvokeRequired Then
            Labels(LabelNum).Invoke(Delegate_label, New Object() {nText, Labels(LabelNum)})
        Else
            Labels(LabelNum).Text = nText
            Labels(LabelNum).Update()
        End If

    End Sub
End Class

所以,现在在改版后的bodacc_data以及所有其他处理类我只有:

Public Class bodacc_data
    ......
    Private MyUI as Form_UI
    .....
    Sub New()
        MyUI = New Form_UI()
    End Sub

    Sub ResyncFTP()
        //says hello
        MyUI.ChangeLabel(1, "Working...")

        //do stuff
    End Sub
End Class

问题为什么MyUI.ChangeLabel在线程中调用ResyncFTP时不更新,但如果在主线程中调用则有效(如下面的代码示例中所示)< / p>

Private Sub Button11_Click(sender As Object, e As EventArgs) Handles Button11.Click
    Dim MyBodacc As bodacc_data = New bodacc_data 
    MyBodacc.ResyncFTP()
End Sub

请注意,没有抛出任何错误。值得注意的奇怪之处是<Form_UI>.ChangeLabel()永远不会进入.Invoke路由,而是正常的更新路由。我强烈怀疑范围问题或洞察力问题。

1 个答案:

答案 0 :(得分:0)

创建Windows窗体应用程序时,您需要设置一个UI线程,该线程应该是所有UI的所有者。 UI线程包含用于更新所有UI的消息泵。

但是你在Button11_Click中正在做的是创建一个新的线程,然后调用Dim MyBodacc As bodacc_data = New bodacc_data,然后调用MyUI = New Form_UI()

您正在非UI线程上创建表单。没有消息泵,因此UI不会更新。