【问题标题】:BackgroundWorker with Dispatcher doesn't seem to do anything带有 Dispatcher 的 BackgroundWorker 似乎没有做任何事情
【发布时间】:2023-03-03 20:48:01
【问题描述】:

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

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

【问题讨论】:

    标签: c# mvvm backgroundworker dispatcher wpf-4.0


    【解决方案1】:

    你有两个问题:

    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 自行执行。它所做的只是安排一个 Dispatcher 回调然后退出。
    3. Dispatcher 回调再次在 UI 线程上执行。它调用 PartialEmployees.Clear() 需要一段时间,在执行时锁定你的 UI 线程。

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

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

    【讨论】:

    • 好吧。也许我很困惑。 BackgroundWorker的目的不是在后台做工作,所以UI不会冻结;然后使用 Dispatcher 将更改编组到 UI 线程?我正在使用 EntityFramework,.Clear() 是为列表内置的。我不想在 UI 线程中工作,我只想“刷新”绑定到 UI 的列表。我在想这可能是不可能的,我只需要输入一个进度条,以便用户知道正在发生某些事情并且应用程序不会被冻结。
    • 在这种情况下,您可能需要将 UI 绑定到不由 EntityFramework 维护的集合,并且当 EntityFramework 集合触发 CollectionChanged 时,使用 Dispatcher.Invoke 在绑定的集合中进行相应的更改,以便 UI 绑定集合在 UI 线程上更新。您对 BackgroundWorker 的目的是正确的,实际上它适合您通过 EntityFramework 加载数据的目的。而且只要你小块更新你的 UI,UI 就不会死机。
    【解决方案2】:

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

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

    【讨论】:

    • 你也可以只做 MainWindow.Dispatcher 或 App.Current.Dispatcher (假设你没有做任何棘手的事情,比如在 > 1 个线程上运行 runloops)
    • 这也不起作用,它似乎在起作用,但 UI 没有改变。我在想我没有使用 UI 调度程序,所以它在不同的线程上完成工作,然后 UI 永远不会知道。我无法执行 MainWindow.Dispatcher,因为“需要对象引用”......不确定这是指什么。
    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2016-04-09
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      • 2019-11-26
      • 2019-12-08
      • 2020-12-21
      • 2023-04-06
      • 2018-04-03
      相关资源
      最近更新 更多