Gab*_*ber 7 c# xaml windows-runtime windows-store-apps
我正在为Windows 8编写Windows Store App玩具应用程序.它只有一个xaml页面TextBlock.该页面的MyTimer类为DataContext:
this.DataContext = new MyTimer();
Run Code Online (Sandbox Code Playgroud)
MyTimer实现INotifyPropertyChanged并Time使用计时器更新属性:
public MyTimer(){
TimerElapsedHandler f = new TimerElapsedHandler(NotifyTimeChanged);
TimeSpan period = new TimeSpan(0, 0, 1);
ThreadPoolTimer.CreatePeriodicTimer(f, period);
}
Run Code Online (Sandbox Code Playgroud)
同
private void NotifyTimeChanged(){
if (this.PropertyChanged != null){
this.PropertyChanged(this, new PropertyChangedEventArgs("Time"));
}
}
Run Code Online (Sandbox Code Playgroud)
在TextBlock对的时间数据绑定
<TextBlock Text="{Binding Time}" />
Run Code Online (Sandbox Code Playgroud)
当我运行应用程序时,我有以下异常:
System.Runtime.InteropServices.COMException was unhandled by user code
Run Code Online (Sandbox Code Playgroud)
随着消息
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"));
});
}
}
}
Run Code Online (Sandbox Code Playgroud)
一种方法是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; } }
}
Run Code Online (Sandbox Code Playgroud)
如果在UI线程上调用构造函数,它也会在PropertyChanged那里调用它.好的是,完全相同的代码也可以在WPF中工作(在.Net 4.5和C#5下).
| 归档时间: |
|
| 查看次数: |
7386 次 |
| 最近记录: |