仅在DispatcherTimer线程完成后才更新WPF接口

时间:2013-06-14 10:08:10

标签: c# .net wpf mvvm

我有一个WPF应用程序,我正在使用.NET Framework 4.0和C#。我的应用程序包含一个带有多个控件的界面。特别是我有一个需要每10秒定期执行一次的任务。为了执行它,我使用System.Windows.Threading.DispatcherTimer。 ViewModel看起来像这样:

public class WindowViewModel {
  protected DispatcherTimer cycle;

  public WindowViewModel() {
    this.cycle = new DispatcherTimer(DispatcherPriority.Normal, 
                 System.Windows.Application.Current.Dispatcher);
    this.cycle.Interval = new TimeSpan(0,0,0,0,10000);
    this.cycle.Tick += delegate(object sender, EventArgs e) {
      for (int i = 0; i < 20; i++) {
        // Doing something
      }
    };
    this.cycle.Start;
  }
}

正如我所说,定期调用的例程会做一些事情。特别是那里有一些重要的逻辑导致该例程花费几秒钟来执行和完成。好吧,这是一个不同的线程,所以我应该没问题,界面不应该冻结。

问题是该例程导致视图模型更新。更新了几个数据,相应的View绑定到这些数据。所发生的是所有更新的数据在例程完成时刷新一次。我希望在线程执行期间更新数据。

特别是在那个例程中,我有一个for周期。在循环的退出处,一切都在界面中更新。怎么做到这一点?我在哪里做错了?

1 个答案:

答案 0 :(得分:3)

DispatcherTimer使用提供的Dispatcher来运行计时器回调。

如果你看一下Dispatcher的文档,就会有一个线索:

  

提供管理 线程

的工作项队列的服务。

因此,通过使用System.Windows.Application.Current.Dispatcher,您将使用管理UI线程的“工作项队列”的Dispatcher。

要在ThreadPool中开展工作,您可以使用System.Threading.Timer或在ThreadPool.QueueUserWorkItem回调中使用DispatcherTimer

如果将此与以下扩展方法结合使用,则在完成繁重的工作量时,可以轻松地将任何特定于UI的内容封送回Dispatcher:

public static class DispatcherEx
{
    public static void InvokeOrExecute(this Dispatcher dispatcher, Action action)
    {
        if (dispatcher.CheckAccess())
        {
            action();
        }
        else
        {
            dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                   action);
        }
    }
}

...然后

this.cycle.Tick += delegate(object sender, EventArgs e) {
  ThreadPool.QueueUserWorkItem(_ => {
     for (int i = 0; i < 20; i++) {
       // Doing something heavy
       System.Windows.Application.Current.Dispatcher.InvokeOrExecute(() => {
          //update the UI on the UI thread.
       });
     }
  });
};