MVVM-Lightを使用するユニバーサル アプリを開発しています。ViewModelsからWebServicesを呼び出し、 WebServicesでViewModelsへの呼び出しで発生した例外をスローします: TimeOut、Wrong URL、Server Exception、...
MessageDialogを介してこれらの例外ごとに表示されるメッセージを一元化するクラス「ExceptionsMsgHelper.cs 」を作成しました。
私のホームページは、複数のデータを含むピボットに基づいています。一部の Web サービスは非同期的に呼び出されます。クラス「 ExceptionsMsgHelper.cs 」を介して MessageDialog に例外を表示するとクラッシュしますが、以前の例外は別の 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()" を 2 回呼び出すと、"System.UnauthorizedAccessException" 例外が発生します: "Access is denied. (Exception from 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 は 2 番目のダイアログで 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);
});
}
}
=>しかし、この場合も、常に同じ例外が発生します。
- ここで説明するように、拡張機能を使用して messagedialogs をキューに入れます(複数の 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
}
=>そして、これは私にとってはうまくいきます。
しかし、それは著者だと言うように、それはおそらく最善の解決策ではありません:
新しいダイアログを開く必要がある場合は、既存のダイアログを閉じます。これは最も簡単なオプションであり、おそらく最良の方法ですが、ダイアログの内容によっては何らかの重要なダイアログをキャンセルするリスクがあります。古いダイアログが閉じられないようにダイアログをキューに入れますが、古いダイアログが閉じられた後に新しいダイアログが表示されます。これにより、すべてのダイアログがユーザーによって閉じられるようになりますが、アプリが何百ものダイアログを表示し始めることができる場合、これは問題になる可能性があります。まだ表示されていない場合にのみ、新しいものを開きます。現在、これは新しいメッセージが表示されないリスクがあり、最初のオプションよりも問題があるように聞こえます。
=> より適応していると思われる最初の 2 つの解決策を適用できない理由を理解したい