Windowsapp storeUI更新

我正在为Windows 8编写Windows Store App玩具应用程序。它只有一个带有TextBlock xaml页面。 该页面具有MyTimer类作为DataContext

 this.DataContext = new MyTimer(); 

MyTimer实现INotifyPropertyChanged并使用计时器更新属性Time

 public MyTimer(){ TimerElapsedHandler f = new TimerElapsedHandler(NotifyTimeChanged); TimeSpan period = new TimeSpan(0, 0, 1); ThreadPoolTimer.CreatePeriodicTimer(f, period); } 

 private void NotifyTimeChanged(){ if (this.PropertyChanged != null){ this.PropertyChanged(this, new PropertyChangedEventArgs("Time")); } } 

TextBlock在Time上有一个数据绑定

  

当我运行应用程序时,我有以下exception:

 System.Runtime.InteropServices.COMException was unhandled by user code 

随着消息

The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

真正的问题是我正在更新MyTimer类的属性,而不是GUI本身,我无法弄明白,但我认为解决方案应该使用类似这样的东西。

是的,您正在通过线程池线程而不是UI线程通知属性更改。 您需要将通知编组回计时器回调中的UI线程。 现在,您的视图模型与您的视图分离(一件好事),因此它没有与Dispatcher基础结构的直接链接。 所以你想做的就是把它交给正确的SynchronizationContext进行通信。 为此,您需要在构造期间捕获当前的SynchronizationContext ,或者允许它显式传递给适合测试的构造函数,或者如果您要从UI线程开始初始化对象。

整个shebang看起来像这样:

 public class MyTimer { private SynchronizationContext synchronizationContext; public MyTimer() : this(SynchronizationContext.Current) { } public MyTimer(SynchronizationContext synchronizationContext) { if(this.synchronizationContext == null) { throw new ArgumentNullException("No synchronization context was specified and no default synchronization context was found.") } TimerElapsedHandler f = new TimerElapsedHandler(NotifyTimeChanged); TimeSpan period = new TimeSpan(0, 0, 1); ThreadPoolTimer.CreatePeriodicTimer(f, period); } private void NotifyTimeChanged() { if(this.PropertyChanged != null) { this.synchronizationContext.Post(() => { this.PropertyChanged(this, new PropertyChangedEventArgs("Time")); }); } } } 

一种方法是在循环中等待Task.Delay()而不是使用计时器:

 class MyTimer : INotifyPropertyChanged { public MyTimer() { Start(); } private async void Start() { while (true) { await Task.Delay(TimeSpan.FromSeconds(1)); PropertyChanged(this, new PropertyChangedEventArgs("Time")); } } public event PropertyChangedEventHandler PropertyChanged = delegate { }; public DateTime Time { get { return DateTime.Now; } } } 

如果在UI线程上调用构造函数,它也会在那里调用PropertyChanged 。 好的是,完全相同的代码也适用于WPF(在.Net 4.5和C#5下)。

这个博客的代码怎么样:

http://metrowindows8.blogspot.in/2011/10/metro-tiles.html

这对我有用。 我必须将ThreadPoolTimer对象传递给我的委托函数