1

我有一个 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循环。那么在循环退出时,界面中的所有内容都会更新。如何做到这一点?我在哪里做错了?

4

1 回答 1

2

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

如果您查看 的文档Dispatcher,就会发现一条线索:

提供用于管理线程工作项队列的服务。

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

相反,要运行您的工作ThreadPool,您可以在回调中使用System.Threading.Timer或使用。ThreadPool.QueueUserWorkItemDispatcherTimer

如果将其与以下扩展方法结合使用,则在完成繁重的工作负载后,很容易将任何 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.
       });
     }
  });
};
于 2013-06-14T10:22:50.433 回答