3

我正在尝试更新ObservableCollection绑定到 UI 的数据。我知道要做到这一点,我需要使用Dispatcherand BeginvInvoke(),并使其在我这样做时 UI 不会冻结,使用 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();
        }));
} 

但是 UI 没有任何反应。我错过了什么/做得不对?

4

3 回答 3

3

你有两个问题:

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

  2. 根据您的描述,我了解到您的PartialEmployees.Clear()方法需要大量时间才能执行,并且您希望避免在执行期间锁定 UI 线程。但是,在 UI 线程上调用 BackgroundWorkerPartialEmployees.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 自行执行。它所做的只是安排一个 Dispatcher 回调然后退出。
  3. Dispatcher 回调再次在 UI 线程上执行。它调用 PartialEmployees.Clear() 需要一段时间,在它执行时锁定你的 UI 线程。

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

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

于 2010-11-17T18:02:13.360 回答
1

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

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

...
private void DoWork(Dispatcher dispatcher) {
  dispatcher.BeginInvoke(new Action(() => {
    PartialEmployees.Clear();
  });
}
于 2010-11-17T17:18:12.090 回答
0

我认为您不需要后台工作,就像在Threadpool 线程BeginInvoke上运行一样。Dispatcher

像这样的东西应该可以工作,而且更简洁

DispatcherTimer dispTimer = new DispatcherTimer 
    {Interval = TimeSpan.FromSeconds(45)};
dispTimer.Tick += (o,e) => Dispatcher.CurrentDispatcher
    .BeginInvoke((Action)PartialEmployees.Clear);
dispTimer.Start();
于 2010-11-19T15:09:27.330 回答