Windows 应用商店应用 UI 更新 [英] Windows Store App UI update

查看:43
本文介绍了Windows 应用商店应用 UI 更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing a Windows Store App toy application for Windows 8. It has just one xaml page with a TextBlock. The page has the class MyTimer as DataContext :

this.DataContext = new MyTimer();

MyTimer 实现了 INotifyPropertyChanged 并且属性 Time 的更新是通过一个计时器完成的:

MyTimer implements INotifyPropertyChanged and the updating of the property Time is made with a timer:

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 在时间上有一个数据绑定

the TextBlock has a databinding on Time

<TextBlock Text="{Binding Time}" />

当我运行应用程序时,出现以下异常:

When I run the application i have the following exception:

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

随着消息

应用程序调用了一个为不同线程编组的接口.(来自 HRESULT 的异常:0x8001010E (RPC_E_WRONG_THREAD))

真正的问题是我正在更新类 MyTimer 的属性,而不是 GUI 本身,我想不通,但我认为解决方案应该使用这个之类的东西.

The real problem is that I am updating the property of the class MyTimer, not the GUI itself, I can't figure it out, but I think the solution should use something like this one.

推荐答案

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

Yes, you're notifying property changes from a thread pool thread rather than the UI thread. You need to marshal the notification back to the UI thread in the timer callback. Now, your view model is separated from your view (a good thing) therefore it doesn't have a direct link to the Dispatcher infrastructure. So what you want to do is hand it the proper SynchronizationContext on which to communicate. To do this you need to capture the current SynchronizationContext during construction or allow it to be passed in explicitly to a constructor which is good for tests or if you're initializing the object off the UI thread to begin with.

整个shebang看起来像这样:

The whole shebang would look something like this:

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"));
                });
        }
    }
}

这篇关于Windows 应用商店应用 UI 更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆