这可能不完全准确,但以下是我通过一些测试和来自
Reference Source
:
没有/在实例化
ProgressBar
WebClient
配合
SynchronizationContexts
为了将数据发布回UI线程并调用其事件处理程序(如
BackgroundWorker
Async
方法
立即创建绑定到的异步操作
SynchronizationContext
调用线程的。如果上下文不存在,将创建一个新的上下文并将其绑定到该线程。
RunWorkerAsync
没有(或之前)创建
进度条
幕后工作者
这是我的线。
创建
进度条
之前
和
进度条
在开始下载之前,实例化代码已经就位。现在,您正在非UI线程中创建一个控件,这将导致一个新的
行绪
行绪
有点不同,因为它是一个
WindowsFormsSynchronizationContext
Control.Invoke()
和
Control.BeginInvoke()
这似乎是出问题的地方。通过在非UI线程中创建控件,从而创建
WindowsFormsSynchronizationContext
在该线程中
现在将在调用事件处理程序时使用该上下文。这个
将呼叫
WindowsFormsSynchronizationContext.Post()
Control.BeginInvoke()
在同步上下文的线程上执行该调用。唯一的问题是:该线程没有处理
BeginInvoke
消息
最后,这一切再一次归结为WinForms的黄金法则:
将所有与UI相关的工作留在UI线程上!
编辑:
对于异步方法,您可以这样解决它,并让
在UI线程上创建,然后为您返回:
Dim AddRPB As ProgressBar = Me.Invoke(Function() New ProgressBar)
AddHandler client.DownloadProgressChanged, AddressOf DownloadingProgress
AddHandler client.DownloadDataCompleted, AddressOf DownloadComplete
client.DownloadDataAsync(New Uri(WebLink), AddRPB)