C# 如何在异步方法中以同步方式更新UI线程上的元素?

C# 如何在异步方法中以同步方式更新UI线程上的元素?,c#,async-await,windows-phone-8,portable-class-library,C#,Async Await,Windows Phone 8,Portable Class Library,我正在开发一个应用程序,并试图把每件事都做得很好,做到最佳实践;以下代码不符合我的要求: async public Task DoStuff() { DispatcherAdapter.Current.BeginInvoke(() => { myObject.SomeProperty = "new value"; }); await DatabaseAdapter.Current.SaveItem(TableName, myObject); } 上面的代码没有使用更新的属

我正在开发一个应用程序,并试图把每件事都做得很好,做到最佳实践;以下代码不符合我的要求:

async public Task DoStuff()
{
    DispatcherAdapter.Current.BeginInvoke(() => { myObject.SomeProperty = "new value"; });
    await DatabaseAdapter.Current.SaveItem(TableName, myObject);
}
上面的代码没有使用更新的属性值将项保存到数据库中,我想这是因为BeginInvoke()不一定在等待的异步方法完成其工作之前完成。DispatcherAdapter只是在后台使用Deployment.Current.Dispatcher,如下所示:

    public override void BeginInvoke(Action a)
    {
        Deployment.Current.Dispatcher.BeginInvoke(a);
    }
以下是我调查过的,但不起作用:

  • 等待BeginInvoke()调用-不会工作,因为它不会返回任务,而且它仍然会深入到无法确定Dispatcher.BeginInvoke实际何时完成
  • -正常.NET中可用的已完成事件不适用于Windows Phone 8
  • -DispatchersSynchronizationContext。当前值始终为空,因此不起作用…请参阅下面的无关代码:

    public async override Task Invoke(Action a)
    {
        await Task.Factory.StartNew(() => { DispatcherSynchronizationContext.Current.Send(new SendOrPostCallback(delegate { a.Invoke(); }), null); });
    }
    

基本上,在WindowsPhone8中,如何避免无效的跨线程访问并确保代码在异步方法中以特定顺序运行?我想我可以将.SaveItem移动到BeginInvoke中…但这感觉像是一个欺骗的出路,我仍然不能等待BeginInvoke调用(这使得将它放在异步方法中变得毫无意义)如果能知道在这种情况下我应该做什么/其他人已经做了什么,那就太好了。

我最终创建了自己的DispatcherSynchronizationContext,一切似乎都正常:

    public async override Task Invoke(Action a)
    {
        DispatcherSynchronizationContext dsc = new DispatcherSynchronizationContext(Deployment.Current.Dispatcher);
        await Task.Factory.StartNew(() => { dsc.Send(new SendOrPostCallback(delegate { a.Invoke(); }), null); });
    }

我仍然不确定这是否是推荐的方法,或者以这种方式使用DispatcherSynchronizationContext是否存在任何问题……但是我可以等待这个影响UI线程的帮助器方法,所以这是一个开始…

最简单的方法是从UI线程调用您的
async
方法。然后你可以这样做:

public async Task DoStuffAsync()
{
  myObject.SomeProperty = "new value";
  await DatabaseAdapter.Current.SaveItem(TableName, myObject);
}

如果您的
async
方法需要在后台线程上执行某些操作,请将其包装在
任务中。运行

我不确定是否可以确保从UI线程调用它,因为我的目标是将代码保存在可移植类库中(即视图模型中),从逻辑上讲,视图模型对象不是视图,而是UI上下文的一部分,这主要是由于数据绑定。这是我所有的
async
MVVM项目所采用的方法-它比依赖于
Dispatcher
相关类型更易于测试和移植。