编辑解决方案:
这里我在每个对象中设置我的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部分结束以设置值。
答案 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线程解除阻止所有“不需要”后才会出现。