如何按 FIFO 顺序序列化可等待的任务
本文关键字:等待 任务 序列化 何按 FIFO 顺序 | 更新日期: 2024-10-25 20:22:08
在我的 WinRT 应用中,UI 允许用户单击列表项以开始从服务器下载预览。当列表项处于此下载状态时,列表项模板中将显示一个进度栏。因此,UI 不会被阻止,用户可以自由单击其他项目并开始(并发)下载这些项目。
当下载失败时(例如由于网络连接),它会向 UI 发送一条消息。UI 通过显示消息对话框来处理此消息:
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();
}
问题是,如果 UI 尝试在用户关闭第一条消息之前显示另一条消息,则对 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线程)任务?
谁能指出我正确的方向?
我想做的是序列化对此的访问
最简单的解决方案是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 的后台任务。