jok*_*efe 2 c# popup windows-8 windows-runtime winrt-async
如果ShowAsync在MessageDialog对象上调用该命令时,另一个MessageDialog对象已经显示给用户但未被解除(即当另一个对象已经启动时显示弹出窗口),UnauthorizedAccessException则抛出一个.当您有多个线程试图同时提醒用户时,这可能会使事情变得困难.
我当前的(权宜之计)解决方案只是ShowAsync用try/catch块包围调用并吞下异常.这不期望地导致用户错过后续通知.我能想到的另一种方法是手动实现某种弹出队列.这似乎是工作了过多的量,但考虑到其他框架(如Windows电话)没有这个问题,只会显示层出不穷的弹出一个为用户解除他们.
有没有其他方法可以解决这个问题?
Dav*_*its 11
您可以使用此扩展方法轻松完成:
public static class MessageDialogShower
{
private static SemaphoreSlim _semaphore;
static MessageDialogShower()
{
_semaphore = new SemaphoreSlim(1);
}
public static async Task<IUICommand> ShowDialogSafely(this MessageDialog dialog)
{
await _semaphore.WaitAsync();
var result = await dialog.ShowAsync();
_semaphore.Release();
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
有很多方法可以接近它,选择可能取决于您的技能,要求和偏好.
我个人的选择是完全避免使用对话框,因为它们对用户体验不利(邪恶).然后有替代解决方案,例如显示单独的屏幕/页面,UI需要用户在真正需要时提供一些输入,或者如果用户输入是可选的并且隐藏它,则在侧面/边缘/角落的某处显示非模态弹出窗口片刻之后或其他一些不会破坏用户流量的通知.
如果您不同意或没有时间,资源或技能来实现替代方案 - 您可以在MessageDialog.ShowAsync()调用任何队列时创建某种包装,或者在已显示对话框时忽略新请求.
此类具有扩展方法,允许在已显示另一个对话框时忽略新的显示请求或对请求进行排队:
/// <summary>
/// MessageDialog extension methods
/// </summary>
public static class MessageDialogExtensions
{
private static TaskCompletionSource<MessageDialog> _currentDialogShowRequest;
/// <summary>
/// Begins an asynchronous operation showing a dialog.
/// If another dialog is already shown using
/// ShowAsyncQueue or ShowAsyncIfPossible method - it will wait
/// for that previous dialog to be dismissed before showing the new one.
/// </summary>
/// <param name="dialog">The dialog.</param>
/// <returns></returns>
/// <exception cref="System.InvalidOperationException">This method can only be invoked from UI thread.</exception>
public static async Task ShowAsyncQueue(this MessageDialog dialog)
{
if (!Window.Current.Dispatcher.HasThreadAccess)
{
throw new InvalidOperationException("This method can only be invoked from UI thread.");
}
while (_currentDialogShowRequest != null)
{
await _currentDialogShowRequest.Task;
}
var request = _currentDialogShowRequest = new TaskCompletionSource<MessageDialog>();
await dialog.ShowAsync();
_currentDialogShowRequest = null;
request.SetResult(dialog);
}
/// <summary>
/// Begins an asynchronous operation showing a dialog.
/// If another dialog is already shown using
/// ShowAsyncQueue or ShowAsyncIfPossible method - it will wait
/// return immediately and the new dialog won't be displayed.
/// </summary>
/// <param name="dialog">The dialog.</param>
/// <returns></returns>
/// <exception cref="System.InvalidOperationException">This method can only be invoked from UI thread.</exception>
public static async Task ShowAsyncIfPossible(this MessageDialog dialog)
{
if (!Window.Current.Dispatcher.HasThreadAccess)
{
throw new InvalidOperationException("This method can only be invoked from UI thread.");
}
while (_currentDialogShowRequest != null)
{
return;
}
var request = _currentDialogShowRequest = new TaskCompletionSource<MessageDialog>();
await dialog.ShowAsync();
_currentDialogShowRequest = null;
request.SetResult(dialog);
}
}
Run Code Online (Sandbox Code Playgroud)
测试
// This should obviously be displayed
var dialog = new MessageDialog("await ShowAsync", "Dialog 1");
await dialog.ShowAsync();
// This should be displayed because we awaited the previous request to return
dialog = new MessageDialog("await ShowAsync", "Dialog 2");
await dialog.ShowAsync();
// All other requests below are invoked without awaiting
// the preceding ones to complete (dialogs being closed)
// This will show because there is no dialog shown at this time
dialog = new MessageDialog("ShowAsyncIfPossible", "Dialog 3");
dialog.ShowAsyncIfPossible();
// This will not show because there is a dialog shown at this time
dialog = new MessageDialog("ShowAsyncIfPossible", "Dialog 4");
dialog.ShowAsyncIfPossible();
// This will show after Dialog 3 is dismissed
dialog = new MessageDialog("ShowAsyncQueue", "Dialog 5");
dialog.ShowAsyncQueue();
// This will not show because there is a dialog shown at this time (Dialog 3)
dialog = new MessageDialog("ShowAsyncIfPossible", "Dialog 6");
dialog.ShowAsyncIfPossible();
// This will show after Dialog 5 is dismissed
dialog = new MessageDialog("ShowAsyncQueue", "Dialog 7");
dialog.ShowAsyncQueue();
// This will show after Dialog 7 is dismissed
dialog = new MessageDialog("ShowAsyncQueue", "Dialog 8");
dialog.ShowAsyncQueue();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3228 次 |
| 最近记录: |