编辑解决方案 :
在这里,我在每个对象中设置我的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
这是我的下载文件功能:请注意,每次启动都将执行 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 线程中设置一个标签。 出于某种原因,调用要求永远不会更改为 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 控件的属性。这是我的对象,其中内容地址函数将下载文件(下载我)
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
问题是调用要求永远不会达到 false,它实际上进入 beginInvoke 但永远不会在 Else 部分结束以设置值。
最初的方法 TelechargeFichier() 是从哪里发射的? 它是在主 UI 线程本身中吗?
如果是这样,那么这部分是一个问题:
For i As Integer = 0 To m_listeThreads.Count - 1
m_listeThreads(i).Join()
Next
这是冻结主线程,直到其他线程完成。 这符合您的症状"它实际上进入开始调用,但永远不会在 Else 部分结束以设置值。 由于主 UI 线程被冻结,等待其他线程完成,它不可能执行您对 BeginInvoke() 的请求。
如果要使用 Join() 并等待其他线程完成,请在 BackgroundWorker() 或其他不是主 UI 线程的合适线程的 DoWork() 处理程序中执行此操作。
有了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 线程取消阻止后,才会出现所有"不需要"。