交叉异常和调用所需的解决方案不会更改我的控制值

时间:2013-10-24 20:01:47

标签: vb.net multithreading winforms

编辑解决方案:

这里我在每个对象中设置我的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

这是crossthread调用解决方案函数:

    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部分结束以设置值。

2 个答案:

答案 0 :(得分: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线程的合适线程中执行此操作。

答案 1 :(得分: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线程解除阻止所有“不需要”后才会出现。