MessageDialog - 需要等待用户输入

时间:2013-06-24 11:55:04

标签: c# microsoft-metro async-await messagedialog

我有一个ViewModel,它在同步方法中实例化一个事件。该事件向UI发出信号,表示在继续之前我们需要用户回答“是”或“否”。

我正在尝试显示MessageDialog并等到用户提供答案 - 是或否。我很难做到这一点。我在尝试这样做时目前得到UnauthorizedAccessException

以下是UI中的代码:

async Task<bool> Instance_SwitchConfirmation(string question)
{
    MessageDialog md = new MessageDialog(question);
    md.Commands.Add(new UICommand("Yes", CommandInvokedHandler));
    md.Commands.Add(new UICommand("No", CommandInvokedHandler));
    md.ShowAsync();

    return this.canSwitch;
}

async void CommandInvokedHandler(IUICommand command)
{
    this.canSwitch = command.Label == "Yes" ? true : false;
}

我试过了:

var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => {
    MessageDialog md = new MessageDialog(question);
    md.Commands.Add(new UICommand("Yes", CommandInvokedHandler));
    md.Commands.Add(new UICommand("No", CommandInvokedHandler));
    md.ShowAsync();
}, 
new System.Threading.CancellationToken(), 
TaskCreationOptions.PreferFairness, uiContext);

但是失败了同样的例外。

最后,如果我只是等待MessageDialog,那么就不会显示对话框并且UI线程会被锁定。

MessageDialog md = new MessageDialog(question);
md.Commands.Add(new UICommand("Yes", CommandInvokedHandler));
md.Commands.Add(new UICommand("No", CommandInvokedHandler));
await md.ShowAsync();

如果MessageDialog的同步版本为Show(),我会没事的,但是MessageDialog的异步behvaior加上我的同步例程,再加上交叉线程让我感到困惑。我想知道在我的后端ViewModel中继续使用同步方法之前,是否有人可以概述我需要做什么来等待MessageDialog上的用户输入。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:8)

请参阅Win8 C# Metro dispatcher and RPC_E_WRONG_THREADCoreDispatcher.RunAsync

由于您的方法未在Dispatcher上执行,因此您需要手动调用其上的代码。为了避免重构为回调模式,您可以使用TaskCompletionSource(T)设置结果,后台线程将在设置结果后继续。

var tcs = new TaskCompletionSource<bool>();
var dialogTask = tcs.Task;

MessageDialog md = new MessageDialog(question);
md.Commands.Add(new UICommand("Yes"));
md.Commands.Add(new UICommand("No"));

Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => {
    var result = await md.ShowAsync();
    var canSwitch = result.Label == "Yes";
    tcs.SetResult(canSwitch);
});

var result = await dialogTask;
return result;