gpt4 book ai didi

c# - BackgroundWorker.ProgressChanged 事件不在调度程序线程上

转载 作者:行者123 更新时间:2023-11-30 17:03:19 25 4
gpt4 key购买 nike

我有以下代码从后台 worker 更新我的进度条和状态栏。我运行同一个后台工作程序两次。我第一次运行它时,我从 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);

当从计时器调用它时,出现以下错误:

A first chance exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll Additional information: The calling thread cannot access this object because a different thread owns it.

我添加了一些调试,实际上 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();
}
}

Current Thread: 22 Dispatcher Thread: 7

我的印象是 ProgressChangedRunWorkerCompleted 事件总是在主 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 的全部意义在于我不必执行此操作。有人可以解释我不正确的假设以及到底发生了什么。有没有办法通过以不同方式设置计时器来在没有调度程序的情况下执行此操作?

谢谢,

哈里森

最佳答案

I was under the impression that the ProgressChanged and RunWorkerCompleted events always ran on the main UI thread in order to solve this problem and be able to do UI updates. Apparently, I misunderstand what is going on here.

BackgroundWorkers ProgressChanged 被回调到拥有 BackroundWorker 的线程,这并没有离开 UI 线程,当您第二次创建 BackgroundWorker 时,它是在另一个线程上创建的,因此 ProgressChanged 将在创建 BackgroundWorker 的线程上调用,在本例中为计时器线程。

  • 第一次调用:UIThread => BacgroundWorker => Progress => UIThread
  • SecondCall: TimerThread => BacgroundWorker => Progress => TimerThread

您可以从 Timer 调用 RefreshWebDataTimer 到 UI 线程,或者使用 DispatcherTimer 来确保 RefreshWebDataTimer 在 UI 线程上被调用。

选项 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);

关于c# - BackgroundWorker.ProgressChanged 事件不在调度程序线程上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18709532/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com