Я разрабатываю универсальное приложение, использующее MVVM-Light. Я вызываю WebServices из ViewModels и выбрасываю исключения, возникающие при вызовах WebServices, в ViewModels: TimeOut, Wrong URL, Server Exception,...
Я создал класс "ExceptionsMsgHelper.cs", который централизует сообщения, отображаемые для каждого из этих исключений, через MessageDialog.
Моя домашняя страница основана на Pivot, содержащем несколько данных: некоторые веб-службы вызываются асинхронно. Поэтому я встречаю сбой, если я показываю исключение в MessageDialog через класс «ExceptionsMsgHelper.cs», тогда как предыдущее исключение также отображается в другом MessageDialog.
Вот часть моего исходного класса:
public class ExceptionsMsgHelper
{
public async static void MsgboxWebserviceErrors(WebServiceErrorsException wseE, string errors)
{
Windows.UI.Popups.MessageDialog msgbox =
new Windows.UI.Popups.MessageDialog("The Websercice '" + wseE.WebService + "' has returned errors : \n" + errors,
"Unexpected data");
await msgbox.ShowAsync();
}
}
=> Если я дважды вызываю "msgbox.ShowAsync()", я получаю исключение "System.UnauthorizedAccessException": с сообщением "Доступ запрещен. (Исключение из HRESULT: 0x80070005 (E_ACCESSDENIED))"< /эм>сильный>
Я так искал решения, чтобы исправить это:
- используйте «Dispatcter», как это рекомендуется здесь (WinRT — MessageDialog.ShowAsync выдаст UnauthorizedAccessException в моем пользовательском класс)
Код:
public class ExceptionsMsgHelper
{
public async static void MsgboxWebserviceErrors(WebServiceErrorsException wseE, string errors)
{
Windows.UI.Popups.MessageDialog msgbox =
new Windows.UI.Popups.MessageDialog("The Websercice '" + wseE.WebService + "' has returned errors : \n" + errors,
"Unexpected data");
CoreDispatcher dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
await msgbox.ShowAsync();
});
}
}
=> Но я всегда сталкиваюсь с одним и тем же исключением.
- используйте команду "IAsyncOperation", чтобы закрыть предыдущий MessageDialog, как это рекомендовано здесь (MessageDialog ShowAsync выдает исключение accessdenied на втором диалоговое окно)
С этим кодом:
public class ExceptionsMsgHelper
{
private static IAsyncOperation<IUICommand> messageDialogCommand = null;
public async static Task<bool> ShowDialog(MessageDialog dlg)
{
// Close the previous one out
if (messageDialogCommand != null)
{
messageDialogCommand.Cancel();
messageDialogCommand = null;
}
messageDialogCommand = dlg.ShowAsync();
await messageDialogCommand;
return true;
}
public async static void MsgboxWebserviceErrors(WebServiceErrorsException wseE, string errors)
{
Windows.UI.Popups.MessageDialog msgbox =
new Windows.UI.Popups.MessageDialog("The Websercice '" + wseE.WebService + "' has returned errors : \n" + errors,
"Unexpected data");
CoreDispatcher dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
await ShowDialog(msgbox);
});
}
}
=> Но и в этом случае я всегда получаю одно и то же исключение.
- используйте расширение для постановки диалогов сообщений в очередь, как описано здесь (множественный сбой приложения MessageDialog)
Теперь код:
public class ExceptionsMsgHelper
{
public async static void MsgboxWebserviceErrors(WebServiceErrorsException wseE, string errors)
{
Windows.UI.Popups.MessageDialog msgbox =
new Windows.UI.Popups.MessageDialog("The Websercice '" + wseE.WebService + "' has returned errors : \n" + errors,
"Unexpected data");
await MessageDialogExtensions.ShowAsyncQueue(msgbox);
}
}
public static class MessageDialogExtensions
{
private static TaskCompletionSource<MessageDialog> _currentDialogShowRequest;
public static async Task<IUICommand> 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>();
var result = await dialog.ShowAsync();
_currentDialogShowRequest = null;
request.SetResult(dialog);
return result;
}
private static IAsyncOperation<IUICommand> messageDialogCommand = null;
public async static Task<bool> ShowDialog(this MessageDialog dlg)
{
// Close the previous one out
if (messageDialogCommand != null)
{
messageDialogCommand.Cancel();
messageDialogCommand = null;
}
messageDialogCommand = dlg.ShowAsync();
await messageDialogCommand;
return true;
}
#endregion
}
=> И это работает для меня.
Но, как говорит автор, это, вероятно, не лучшее решение:
Закройте существующий диалог, когда вам нужно открыть новый. Это самый простой вариант и, возможно, лучший, хотя вы рискуете отменить диалог, который может быть каким-то важным в зависимости от того, о чем ваши диалоги. Ставьте диалоги в очередь, чтобы старые не удалялись, а новые появлялись после закрытия старых. Это гарантирует, что все диалоги будут закрыты пользователем, но это может быть проблемой, если ваше приложение может каким-то образом начать показывать сотни диалогов. Открывайте новый только в том случае, если он еще не отображен. Теперь существует риск того, что более новое сообщение не будет показано, что звучит более проблематично, чем первый вариант.
=> Я хотел бы понять, почему я не могу применить одно из двух первых решений, которые кажутся более адаптированными