3

我正在开发一个应用程序并尝试将所有事情都做得很好和最佳实践;这是符合我要求的代码:

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 何时实际完成
  • 尝试使用从 BeginInvoke() 返回的 DispatcherOperation 对象- 在普通 .NET 中可用的 Completed 事件不适用于 Windows Phone 8
  • 使用 SynchronizationContext.Send() - DispatcherSynchronizationContext.Current 始终为空,因此不起作用...请参阅下面的不相关代码:

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

基本上,如何避免无效的跨线程访问并确保代码在 Windows Phone 8 的异步方法中以特定顺序运行?我想我可以将 .SaveItem 移动到 BeginInvoke 中......但它感觉像是一种作弊方式,我仍然无法等待 BeginInvoke 调用(这使得将它放在异步方法中非常没有意义)它会是很高兴知道我应该做什么/其他人在这种情况下做了什么。

4

2 回答 2

2

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

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

如果您的async方法需要在后台线程上执行一些操作,请将其包装在Task.Run.

于 2012-12-05T13:07:52.913 回答
1

我最终创建了自己的 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 线程的辅助方法,所以这是一个开始...... .

于 2012-12-05T09:27:22.087 回答