C# 异步操作后如何返回UI线程

C# 异步操作后如何返回UI线程,c#,windows-8,windows-phone-8,task-parallel-library,portable-class-library,C#,Windows 8,Windows Phone 8,Task Parallel Library,Portable Class Library,我正在使用MVVM模式为Windows应用商店和Windows Phone 8开发同一应用程序的两个版本。每个应用程序都有自己的视图。Model和ViewModel在可移植类Librarray中共享。我使用TPL任务在模型中执行异步操作。由于可移植类库的限制,我不能使用async和Wait关键字 任务完成后,我想回到UI线程并更新一些属性(这将导致ViewModel和View也更新) 在我看来,这似乎是一个相当普遍的情况,所以我有点困惑,为什么结果会如此困难 我尝试了两种不同的方法: 一个(不起

我正在使用MVVM模式为Windows应用商店和Windows Phone 8开发同一应用程序的两个版本。每个应用程序都有自己的视图。Model和ViewModel在可移植类Librarray中共享。我使用TPL任务在模型中执行异步操作。由于可移植类库的限制,我不能使用async和Wait关键字

任务完成后,我想回到UI线程并更新一些属性(这将导致ViewModel和View也更新)

在我看来,这似乎是一个相当普遍的情况,所以我有点困惑,为什么结果会如此困难

我尝试了两种不同的方法:

一个(不起作用)

在开始操作之前保存对计划程序的引用

TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
然后通过方法将其传递给
continue

myTask.ContinueWith(t => myTaskCompleted(t.Result), scheduler);
在我看来,这似乎是一个很好的解决方案,但不起作用。myTaskCompleted仍在另一个线程中执行

现在我试着用

Dispatcher.RunAsync(CoreDispatcherPriority.Normal, handler);
因为我不能直接从PCL使用Dispatcher,所以我将对它的引用(隐藏在包装器中)传递给模型中的几乎每个对象。(像这样)这终于奏效了,但它相当复杂和丑陋

因此,我的问题是:

  • 在可移植类Libraray中,返回UI线程的推荐方法是什么
  • 我试一次的错误是什么

  • 我知道这个主题已经有很多问题,但不幸的是,没有什么真正解决了我的问题。

    TPL将使用线程池中的线程,UI线程是“主线程”,它不在线程池中,永远无法运行任务。使用ContinueWith函数将从线程池中获取另一个线程,以便在执行时执行代码。您面临的核心问题是,Windows Phone不会对属性更改进行排队,而是会直接尝试更新视图。在代码中的某个地方,您应该有一个已更改的函数,用于广播属性更改。我会用我的:

    public void Changed(string Key) {
        // Check if the property changed has subscribers.
        if (PropertyChanged != null) {
            // Invoke the property changed.
            PropertyChanged(this, new PropertyChangedEventArgs(Key));
        }
    }
    
    此更改的函数在WPF应用程序下可以正常工作,因为WPF将对属性更改进行排队,并在下一次UI框架更新时处理它们。由于Windows Phone没有,我们需要建立一个模式来在运行时更改此行为。我创建了一个名为Dispatcher的属性,允许在运行时设置它。我所有的广播现在都由“更改”改为“调度”

    ViewModelStore是我在所有视图模型中使用的通用类,因此此函数允许我将线程安全广播机制附加到所有视图模型。DependencyObject是一个UI组件,例如视图。现在,您真正需要做的就是在视图模型上调用attach

    ProviderViewModel.Attach(this); // This is inside a Page.
    

    所有广播都不会委托给UI线程,而是在UI进入的下一帧调用,并相应地更新所有内容。您不必像这样担心线程安全,但需要记住在Windows Phone应用程序中附加视图模型的新实例。如果还有其他问题,请告诉我,祝你好运

    第一次尝试时代码的上下文是什么?请记住,如果当前不在UI线程中,则
    TaskScheduler.FromCurrentSynchronizationContext()
    不会获取UI线程的上下文。如果你已经在一个背景线程中,那就太晚了,你需要早点抓住它。你有没有调查过?您的第一种方法在我看来是正确的-除非@Servy建议您的
    FromCurrentSynchronizationContext
    没有在UI线程上运行。那么。。。突然间,它似乎起了作用。我不知道上次是怎么回事。我投票结束了这个问题。谢谢你的链接。错误:我是从
    应用程序
    构造函数(Windows应用商店应用程序)开始的。此时,
    TaskScheduler.FromCurrentSynchronizationContext()
    为空,因为UI尚未初始化。然后我以错误的方式使用了
    SetSynchronizationContext()
    public static void Attach(this ViewModelStore ViewModelStore, DependencyObject DependencyObject) {
        // Set the changed event dispatcher.
        ViewModelStore.Dispatcher = (Key) => {
            // Begin invoking of an action on the UI dispatcher.
            DependencyObject.Dispatcher.BeginInvoke(() => {
                // Raise the changed event.
                ViewModelStore.Changed(Key);
            });
        };
    }
    
    ProviderViewModel.Attach(this); // This is inside a Page.