带有调度程序的BackgroundWorker似乎没有做任何事情

发布于 2024-10-03 08:16:00 字数 1202 浏览 4 评论 0原文

我正在尝试更新绑定到 UI 的数据的 ObservableCollection。我知道要做到这一点,我需要使用 DispatcherBeginvInvoke(),并使用BackgroundWorker 是一个很好的方法。无论如何,我已经编译并运行了所有这些,但没有任何反应。我需要每 2 分钟左右更新一次 UI,所以我还使用了 DispatcherTimer

这很有效,因为 DispatcherTimer 是 Dispatcher 的一部分,但会冻结 UI:

DispatcherTimer dispTimer = new DispatcherTimer();
dispTimer.Tick += dispTimer_Tick;
dispTimer.Interval = new TimeSpan(0, 0, 45);
dispTimer.Start();

private void dispTimer_Tick(object sender, EventArgs e)
{
    PartialEmployees.Clear();          
}

因此,使用 BackgroundWorker 我将其拼凑在一起:

DispatcherTimer dispTimer = new DispatcherTimer();
dispTimer.Tick += dispTimer_Tick;
dispTimer.Interval = new TimeSpan(0, 0, 45);
dispTimer.Start();

private void dispTimer_Tick(object sender, EventArgs e)
{
    BackgroundWorker _worker = new BackgroundWorker();
    _worker.DoWork += DoWork;            
    _worker.RunWorkerAsync();

}

private void DoWork(object sender, DoWorkEventArgs e)
{            
    Dispatcher.CurrentDispatcher.BeginInvoke( new Action(()=> 
        {
            PartialEmployees.Clear();
        }));
} 

但用户界面没有任何反应。我错过了什么/做得不正确吗?

I am trying to update an ObservableCollection that is data bound to the UI. I know that to do this I need to use Dispatcher and BeginvInvoke(), and to make it so that the UI doesn't freeze up when I do so, using a BackgroundWorker is a good way to go about it. In any event, I have all this, compiled and running, but nothing happens. I need to update the UI every 2 minutes or so, so I am also using a DispatcherTimer

This works, because DispatcherTimer is part of Dispatcher, but freezes the UI:

DispatcherTimer dispTimer = new DispatcherTimer();
dispTimer.Tick += dispTimer_Tick;
dispTimer.Interval = new TimeSpan(0, 0, 45);
dispTimer.Start();

private void dispTimer_Tick(object sender, EventArgs e)
{
    PartialEmployees.Clear();          
}

So, using the BackgroundWorker I pieced together this:

DispatcherTimer dispTimer = new DispatcherTimer();
dispTimer.Tick += dispTimer_Tick;
dispTimer.Interval = new TimeSpan(0, 0, 45);
dispTimer.Start();

private void dispTimer_Tick(object sender, EventArgs e)
{
    BackgroundWorker _worker = new BackgroundWorker();
    _worker.DoWork += DoWork;            
    _worker.RunWorkerAsync();

}

private void DoWork(object sender, DoWorkEventArgs e)
{            
    Dispatcher.CurrentDispatcher.BeginInvoke( new Action(()=> 
        {
            PartialEmployees.Clear();
        }));
} 

But nothing happens to the UI. What am I missing/not doing correctly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

独行侠 2024-10-10 08:16:00

您有两个问题:

  1. 当您从后台线程使用 Dispatcher.CurrentDispatcher 时,它获取的是后台线程的 Dispatcher,而不是 UI 线程的 Dispatcher。

  2. 根据您的描述,我了解到您的 PartialEmployees.Clear() 方法需要大量时间来执行,并且您希望避免在执行期间锁定 UI 线程。但是,让 BackgroundWorker 在 UI 线程上调用 PartialEmployees.Clear() 与使用 DispatcherTimer 具有相同的效果,因此您需要一种与您想要的解决方案不同的解决方案。

如果您只想修复 Dispatcher.CurrentDispatcher 问题,只需将当前 Dispatcher 存储在本地变量中,如下所示:

private void dispTimer_Tick(object sender, EventArgs e) 
{
  var uiDispatcher = Dispatcher.CurrentDispatcher;

  BackgroundWorker _worker = new BackgroundWorker(); 
  _worker.DoWork += (sender, e) =>
    uiDispatcher.BeginInvoke(new Action(() =>
    {
      PartialEmployees.Clear();
    }));
  _worker.RunWorkerAsync(); 
} 

这将导致您的 UI 更改生效,但在更改期间它仍然会锁定 UI,就像您没有更改一样使用BackgroundWorker。原因是:

  1. DispatcherTimer 触发,在 UI 线程上执行。它所做的一切(dispTimer_Tick)就是启动一个BackgroundWorker,然后退出。
  2. BackgroundWorker 在其自己的 Therad 上执行。它所做的只是安排调度程序回调,然后退出。
  3. Dispatcher 回调再次在 UI 线程上执行。它调用 PartialEmployees.Clear(),这需要一段时间,并在执行时锁定您的 UI 线程。

因此,您的行为与 DispatcherTimer 回调直接调用 PartialEmployees.Clear() 相同:在每种情况下,耗时的操作都在 UI 线程上执行。

锁定的原因是,每当您在 UI 线程上执行大量工作时,您都会在运行时遇到短暂的锁定。解决方案是将您的工作分成更小的部分,并通过 DispatcherTimer 或 BackgroundWorker 一次完成一个部分。对于您的情况,请检查 PartialEmployees.Clear() 的代码,看看是否可以增量完成。

You have two problems:

  1. When you use Dispatcher.CurrentDispatcher from the background thread, it is getting the background thread's Dispatcher, not the UI thread's Dispatcher.

  2. From your description I gather that your PartialEmployees.Clear() method takes significant time to execute and you want to avoid locking the UI thread during the execution. However, having a BackgroundWorker invoke PartialEmployees.Clear() on your UI thread will have the same effect as using the DispatcherTimer, so you need a different solution than the one you are going for.

If you only want to fix the Dispatcher.CurrentDispatcher problem, just store the current Dispatcher in a local variable like this:

private void dispTimer_Tick(object sender, EventArgs e) 
{
  var uiDispatcher = Dispatcher.CurrentDispatcher;

  BackgroundWorker _worker = new BackgroundWorker(); 
  _worker.DoWork += (sender, e) =>
    uiDispatcher.BeginInvoke(new Action(() =>
    {
      PartialEmployees.Clear();
    }));
  _worker.RunWorkerAsync(); 
} 

This will cause your UI change to work but it will still lock up the UI during the change, exactly as if you had not used BackgroundWorker. The reason for this is:

  1. The DispatcherTimer fires, executing on the UI thread. All it does (dispTimer_Tick) is start a BackgroundWorker and then exit.
  2. The BackgroundWorker executes on its own therad. All it does is schedule a Dispatcher callback and then exit.
  3. The Dispatcher callback executes on the UI thread again. It calls PartialEmployees.Clear() which takes a while, locking up your UI thread while it executes.

So your behavior is the same as if the DispatcherTimer callback had called PartialEmployees.Clear() directly: In each case the time-consuming operation is executed on the UI thread.

The reason for the lockup is that any time you do a large piece of work on the UI thread you will get a momentary lockup while it runs. The solution is to break your work into smaller portions and do them one at a time, either from a DispatcherTimer or a BackgroundWorker. In your case, examine the code for PartialEmployees.Clear() to see if it can be done incrementally.

故事和酒 2024-10-10 08:16:00

这里的问题是您正在使用后台线程中的方法 Dispatcher.CurrentDispatcher 。您需要的是 UI 线程的 Dispatcher 实例。

_worker.DoWork += delegate { DoWork(Dispatcher.CurrentDispatcher); };

...
private void DoWork(Dispatcher dispatcher) {
  dispatcher.BeginInvoke(new Action(() => {
    PartialEmployees.Clear();
  });
}

The problem here is that you're using the method Dispatcher.CurrentDispatcher from the back ground thread. What you need is the Dispatcher instance for the UI thread.

_worker.DoWork += delegate { DoWork(Dispatcher.CurrentDispatcher); };

...
private void DoWork(Dispatcher dispatcher) {
  dispatcher.BeginInvoke(new Action(() => {
    PartialEmployees.Clear();
  });
}
柒夜笙歌凉 2024-10-10 08:16:00

我认为您不需要后台工作,因为 Dispatcher 上的 BeginInvoke 在线程池线程上运行。

像这样的东西应该有效,并且更简洁

DispatcherTimer dispTimer = new DispatcherTimer 
    {Interval = TimeSpan.FromSeconds(45)};
dispTimer.Tick += (o,e) => Dispatcher.CurrentDispatcher
    .BeginInvoke((Action)PartialEmployees.Clear);
dispTimer.Start();

I dont think you need the background work, as BeginInvoke on the Dispatcher runs on a Threadpool thread.

something like this should work, and is more succinct

DispatcherTimer dispTimer = new DispatcherTimer 
    {Interval = TimeSpan.FromSeconds(45)};
dispTimer.Tick += (o,e) => Dispatcher.CurrentDispatcher
    .BeginInvoke((Action)PartialEmployees.Clear);
dispTimer.Start();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文