[英]BackgroundWorker.ProgressChanged event not on Dispatcher Thread
我有以下代码从后台工作者更新我的进度条和状态栏。 我两次运行相同的背景工作者。 我第一次运行它时,我从MainWindow构造函数调用它,它工作正常。 在构造函数的最后,我设置了一个定时器来经常调用该方法。
System.Threading.TimerCallback timerCallback = new System.Threading.TimerCallback(RefreshWebDataTimer);
timer = new System.Threading.Timer(
timerCallback, null,
Dictionary.MS_TIMER_FIRSTREFRESH_PERIOD,
Dictionary.MS_TIMER_REFRESH_PERIOD);
从计时器调用它时,我收到以下错误:
WindowsBase.dll中出现“System.InvalidOperationException”类型的第一次机会异常附加信息:调用线程无法访问此对象,因为另一个线程拥有它。
我添加了一些调试,实际上Dispatcher Thread与计时器和原始运行的同一个线程位于不同的线程上。
private void backgroundWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
System.Diagnostics.Debug.Print("Current Thread: {0}", System.Threading.Thread.CurrentThread.ManagedThreadId);
System.Diagnostics.Debug.Print("Dispatcher Thread: {0}", progressBar.Dispatcher.Thread.ManagedThreadId);
this.progressBar.Visibility = Visibility.Visible;
this.progressBar.Value = e.ProgressPercentage;
if (e.UserState != null)
{
this.statusBar.Text = e.UserState.ToString();
}
}
当前主题:22 Dispatcher Thread:7
我的印象是, ProgressChanged
和RunWorkerCompleted
事件总是在主UI线程上运行,以便解决此问题并能够进行UI更新。 显然,我误解了这里发生了什么。
我更新了我的解决方案以使用Dispatcher,如下所示:
private void backgroundWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
progressBar.Dispatcher.BeginInvoke(new OneArgIntDelegate(updateProgressBar), e.ProgressPercentage);
if (e.UserState != null)
{
progressBar.Dispatcher.BeginInvoke(new OneArgStrDelegate(updateStatusBar), e.UserState.ToString());
}
}
private void updateStatusBar(string Text)
{
this.statusBar.Text = Text;
}
private void updateProgressBar(int ProgressPercentage)
{
this.progressBar.Visibility = Visibility.Visible;
this.progressBar.Value = ProgressPercentage;
}
这个解决方案有效,但我认为BackgroundWorker的重点在于我没有必要这样做。 有人可以解释我不正确的假设以及真正发生的事情。 有没有办法在没有调度员的情况下通过不同的方式设置定时器?
谢谢,
哈里森
我的印象是,ProgressChanged和RunWorkerCompleted事件总是在主UI线程上运行,以便解决此问题并能够进行UI更新。 显然,我误解了这里发生了什么。
BackgroundWorkers ProgressChanged被回调给拥有BackroundWorker的线程,这不是UI线程,当你在另一个线程上创建第二次创建BackgroundWorker
时,将在创建BackgroundWorker
的线程上调用ProgressChanged
在这种情况下,计时器线程。
您可以从Timer
调用RefreshWebDataTimer
到UI线程,或使用DispatcherTimer
确保在UI线程上调用RefreshWebDataTimer
。
选项1:
timer = new System.Threading.Timer(
(o) => Dispatcher.Invoke((Action)RefreshWebDataTimer),
null,
Dictionary.MS_TIMER_FIRSTREFRESH_PERIOD,
Dictionary.MS_TIMER_REFRESH_PERIOD);
选项2:
timer = new DispatcherTimer(
TimeSpan.FromSeconds(1),
DispatcherPriority.Background,
(s, e) => RefreshWebDataTimer(),
Dispatcher);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.