在我的WinRT应用程序中,UI允许用户单击列表项以开始从服务器下载预览。当列表项处于此下载状态时,列表项模板中将显示进度条。因此,UI不会被阻止,用户可以自由地点击其他项目并开始(并发)下载。
当下载失败时(由于网络连接,让我们说),它会向UI发送一条消息。 UI通过显示MessageDialog:
来处理此消息public async void ShowError(string message)
{
var dialog = new MessageDialog(message, "Error")
{
CancelCommandIndex = 0,
DefaultCommandIndex = 0,
Options = MessageDialogOptions.None
};
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
问题是,如果用户界面在用户取消第一条消息之前尝试显示另一条消息,则对MessageDialog.ShowAsync
的调用会抛出System.UnauthorizedAccessException
。
我想要做的是序列化对此的访问,以便第二条消息等待第一条消息,然后显示。第三条消息将等待第二条消息,依此类推。
所有这一切都发生在UI线程上,我不知道如何正确地做到这一点。似乎我希望每个新的错误消息框请求将自己设置为“当前”请求,然后等待解雇“上一个”:
public async void ShowError(string message)
{
...
// *** PSEUDO CODE FOLLOWS ***
// If a message is being displayed...
if (_currentTask != null)
{
// ...wait for that task to complete
_currentTask = NewTaskThatWaitsFor(_currentTask);
await _currentTask;
}
_currentTask = dialog.ShowAsync();
await currentTask;
}
我如何在我之前等待的另一个(UI线程)任务中'附加'自己等待(不阻止 - 这是UI线程)?
有人能指出我正确的方向吗?
答案 0 :(得分:3)
我想要做的是序列化对此
的访问
最简单的解决方案是SemaphoreSlim
:
private readonly SemaphoreSlim _dialogMutex = new SemaphoreSlim(1);
public async void ShowError(string message)
{
await _dialogMutex.WaitAsync();
try
{
var dialog = new MessageDialog(message, "Error")
{
CancelCommandIndex = 0,
DefaultCommandIndex = 0,
Options = MessageDialogOptions.None
};
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
finally
{
_dialogMutex.Release();
}
}
但是,由于我已经写完了,我建议你重新考虑一下这个部分:
当下载失败时(由于网络连接,让我们说),它会向UI发送一条消息。 UI处理此消息...
如果您的后台任务完全不知道UI,我发现代码更清晰。如果您正在使用消息总线,那很好(尽管我从未在需要消息总线的UI应用程序上工作过);但是你要避免的是后台任务直接向UI发送消息。