0

编辑解决方案:

在这里,我在每个对象中设置我的 byref 值,然后我正在运行一个后台工作程序

Private Sub TelechargeFichier()

    Dim DocManquant As Boolean = False
    Dim docName As String = ""
    Dim lg As String = ""
    Dim telechargementFini As Boolean = False

    lblMessage.Text = EasyDealChangeLanguage.Instance.GetStringFromResourceName("1478")

    prgBar.Maximum = m_listeFichiers.Count

    For i As Integer = 0 To m_listeFichiers.Count - 1

        m_listeFichiers(i).Set_ByRefLabel(lblMessage)
        m_listeFichiers(i).Set_ByRefPrgbar(prgBar)
        m_listeThreads.Add(New Thread(AddressOf m_listeFichiers(i).DownloadMe))

    Next


    m_bgWorker = New BackgroundWorker
    m_bgWorker.WorkerReportsProgress = True
    AddHandler m_bgWorker.DoWork, AddressOf DownloadFiles
    m_bgWorker.RunWorkerAsync()







    ''Completed
    'lblMessage.Text = EasyDealChangeLanguage.Instance.GetStringFromResourceName("1383")

    'Me.DialogResult = System.Windows.Forms.DialogResult.OK

End Sub

这是我的 downloadFiles 函数:请注意,每次启动都会执行 downloadMe 函数,如下所示

  Private Sub DownloadFiles(sender As Object, e As DoWorkEventArgs)


    For i As Integer = 0 To m_listeThreads.Count - 1
        m_listeThreads(i).Start()
    Next

    For i As Integer = 0 To m_listeThreads.Count - 1
        m_listeThreads(i).Join()
    Next


End Sub

这里的问题:

我有多个线程,每个线程都会下载一个 ftp 文件。我希望每个已完成的文件都会为进度条和我的 UI 线程中的标签设置一个值。由于某种原因,invokerequired 永远不会更改为 false。

这是我启动所有线程的小功能

 Private Sub TelechargeFichier()

    Dim DocManquant As Boolean = False
    Dim docName As String = ""
    Dim lg As String = ""
    Dim telechargementFini As Boolean = False

    lblMessage.Text = EasyDealChangeLanguage.Instance.GetStringFromResourceName("1478")

    prgBar.Maximum = m_listeFichiers.Count

    For i As Integer = 0 To m_listeFichiers.Count - 1

        m_listeFichiers(i).Set_ByRefLabel(lblMessage)
        m_listeFichiers(i).Set_ByRefPrgbar(prgBar)
        m_listeThreads.Add(New Thread(AddressOf m_listeFichiers(i).DownloadMe))

    Next


    For i As Integer = 0 To m_listeThreads.Count - 1
        m_listeThreads(i).Start()
    Next

    For i As Integer = 0 To m_listeThreads.Count - 1
        m_listeThreads(i).Join()
    Next

    'Completed
    lblMessage.Text = EasyDealChangeLanguage.Instance.GetStringFromResourceName("1383")

    Me.DialogResult = System.Windows.Forms.DialogResult.OK

End Sub

这是我的属性,它保存来自 UI 线程的 Byref 控件。这是在我的对象中,其中包含将下载文件的地址函数(DownloadMe)

    Public Sub Set_ByRefPrgbar(ByRef prgbar As ProgressBar)

    m_prgBar = prgbar

End Sub
Public Sub Set_ByRefLabel(ByRef lbl As EasyDeal.Controls.EasyDealLabel3D)

    m_lblMessage = lbl

End Sub

这是下载功能:

   Public Sub DownloadMe()

    Dim ftpReq As FtpWebRequest
    Dim ftpResp As FtpWebResponse = Nothing
    Dim streamInput As Stream
    Dim fileStreamOutput As FileStream

    Try

        ftpReq = CType(WebRequest.Create(EasyDeal.Controls.Common.FTP_CONNECTION & m_downloadFtpPath & m_filename), FtpWebRequest)
        ftpReq.Credentials = New NetworkCredential(FTP_USER, FTP_PASS)
        ftpReq.Method = WebRequestMethods.Ftp.DownloadFile
        ftpResp = ftpReq.GetResponse
        streamInput = ftpResp.GetResponseStream()
        fileStreamOutput = New FileStream(m_outputPath, FileMode.Create, FileAccess.ReadWrite)
        ReadWriteStream(streamInput, fileStreamOutput)

    Catch ex As Exception

        'Au pire la fichier sera pas downloader

    Finally

        If ftpResp IsNot Nothing Then
            ftpResp.Close()
        End If

        Dim nomFichier As String = m_displaynameEN

        If EasyDealChangeLanguage.GetCurrentLanguageTypes = EasyDealChangeLanguage.EnumLanguageType.Francais Then
            nomFichier = m_displaynameFR

        End If
        If m_lblMessage IsNot Nothing Then
            EasyDealCommon.TH_SetControlText(m_lblMessage, String.Format(EasyDealChangeLanguage.Instance.GetStringFromResourceName("1479"), nomFichier))

        End If
        If m_prgBar IsNot Nothing Then
            EasyDealCommon.TH_SetPrgValue(m_prgBar, 1)

        End If

    End Try



End Sub

这是跨线程调用解决方案功能:

    Public Sub TH_SetControlText(ByVal ctl As Control, ByVal text As String)

    If ctl.InvokeRequired Then

        ctl.BeginInvoke(New Action(Of Control, String)(AddressOf TH_SetControlText), ctl, text)

    Else

        ctl.Text = text

    End If

End Sub
Public Sub TH_SetPrgValue(ByVal prg As ProgressBar, ByVal value As Integer)

    If prg.InvokeRequired Then

        prg.BeginInvoke(New Action(Of ProgressBar, Integer)(AddressOf TH_SetPrgValue), prg, value)

    Else

        prg.Value += value

    End If

End Sub

问题是 invokerequired 永远不会变为 false 它实际上进入 beginInvoke 但永远不会在 Else 部分结束以设置值。

4

2 回答 2

1

初始方法 TelechargeFichier() 是从哪里触发的?它在主 UI 线程本身中吗?

如果是这样,那么这部分是一个问题:

For i As Integer = 0 To m_listeThreads.Count - 1
    m_listeThreads(i).Join()
Next

这是冻结主线程,直到其他线程完成。这符合您的“它实际上进入 beginInvoke 但从未在 Else 部分结束以设置值”的症状。由于主 UI 线程被冻结,等待其他线程完成,它不可能执行您对 BeginInvoke() 的请求。

如果您想要 Join() 并等待其他线程完成,请在 BackgroundWorker() 的 DoWork() 处理程序中执行此操作,或者在不是主 UI 线程的其他合适线程中执行此操作。

于 2013-10-24T20:30:42.960 回答
1

invoke你想“回到” UI 线程,在那里做一些工作。你看过你的 UI 线程是做什么的吗?它启动线程,然后使用.Join. 这将阻塞 UI 线程,直到所有其他线程完成。这意味着您的更新代码无法运行(即使在 begininvoke 之后),因为阻塞的(UI)线程不会运行它;)

Public Class Form1

Private tm As New Threading.Timer(AddressOf tmcallback)

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    tm.Change(0, 500)
    Dim t As New Threading.Thread(Sub() Threading.Thread.Sleep(10000))
    t.Start()
    t.Join()
    tm.Change(-1, -1)


End Sub

Sub tmcallback()
    If Me.InvokeRequired Then
        Console.WriteLine("Required")
        Me.BeginInvoke(Sub() tmcallback())
    Else
        Console.WriteLine("NOT Required")
    End If
End Sub
End Class

注意输出:首先显示所有“必需”,并且只有在 UI 线程解除阻塞后,所有“不需要”才会出现。

于 2013-10-24T20:31:20.860 回答