MessageDialog ShowAsync在第二个对话框上抛出访问被拒绝的异常。

23

我正在尝试在Windows 8中实现“重试/取消”对话框。第一次显示对话框时正常,但是在再次单击“重试”并失败后,调用ShowAsync会导致访问被拒绝的异常。我不知道为什么,有时当我设置断点时,代码可以正常工作且不会出现异常。这里是代码:

    async void DismissedEventHandler(SplashScreen sender, object e)
    {
        dismissed = true;
        loadFeeds();
    }
    private async void loadFeeds()
    {
        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
        {
            try
            {
                RSSDataSource rssDataSource = (RSSDataSource)App.Current.Resources["RSSDataSource"];
                if (rssDataSource != null)
                {
                    await rssDataSource.DownloadFeeds();
                    await rssDataSource.GetFeedsAsync();
                }

                AdDataSource ads = (AdDataSource)App.Current.Resources["AdDataSource"];

                if (ads != null)
                {
                    await ads.DownloadAds();
                }
                rootFrame.Navigate(typeof(HomePageView));

                Window.Current.Content = rootFrame;
            }
            catch
            {
                ShowError();
            }

        });
    }
    async void ShowError()
    {
        // There was likely a problem initializing
        MessageDialog msg = new MessageDialog(CONNECTION_ERROR_MESSAGE, CONNECTION_ERROR_TITLE);

        // Add buttons and set their command handlers
        msg.Commands.Add(new UICommand(COMMAND_LABEL_RETRY, new UICommandInvokedHandler(this.CommandInvokedHandler)));
        msg.Commands.Add(new UICommand(COMMAND_LABEL_CLOSE, new UICommandInvokedHandler(this.CommandInvokedHandler)));
        // Set the command to be invoked when a user presses 'ESC'
        msg.CancelCommandIndex = 0;

        await msg.ShowAsync();
    }

    /// <summary>
    /// Callback function for the invocation of the dialog commands
    /// </summary>
    /// <param name="command">The command that was invoked</param>
    private void CommandInvokedHandler(IUICommand command)
    {
        string buttonLabel = command.Label;
        if (buttonLabel.Equals(COMMAND_LABEL_RETRY))
        {
            loadFeeds();
        }
        else
        {
            // Close app
            Application.Current.Exit();
        }
    }
5个回答

25

好的,我找到了一个快速解决方案,

定义一个IAsyncOperation类变量。

IAsyncOperation<IUICommand> asyncCommand = null;

并将其设置为MessageDialog的ShowAsync方法

asyncCommand = msg.ShowAsync();

在重试/再试的命令处理程序中,检查asyncCommand不为空,并在必要时取消上一次操作。

if(asyncCommand != null)
{
   asyncCommand.Cancel();
}

请告诉我如果有更好的方法。


为了避免出现“使用未分配的本地变量'asyncCommand'”的情况,当asyncCommand被分配时,我不得不将其赋值为null。 - B. Clay Shannon-B. Crow Raven
1
附注:我有自己的任务队列在单个线程中运行,每次只从一个线程中执行一个ShowAsync。显然,如果一个ShowAsync在第一帧结束,而第二个ShowAsync在第二帧开始,可能会出现随机的访问被拒绝错误 :/。手动取消可以解决这个问题。 - RelativeGames
这在我的情况下完美地运行,其中第二个对话框并不是真正嵌套的,而是显示在第一个UICommand的回调操作中。 - Chris Bordeman

9

我来晚了,但是这里有一个方法,您可以始终等待对话框的结果,而且不需要担心连续调用太多对话框:

首先在您的应用程序中定义一个静态变量和方法:

 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;
 }

现在,您可以传递任何对话框并始终等待执行。这就是为什么它返回一个布尔值而不是空值的原因。您无需担心多个之间的冲突。为什么不使此方法接受字符串? 因为您可能会将标题和Yes / No命令处理程序分配到您正在使用的特定对话框中。
例如调用:
await App.ShowDialog(new MessageDialog("FOO!"));

或者

var dlg = new MessageDialog("FOO?", "BAR?");
dlg.Commands.Add(new UICommand("Yes", new UICommandInvokedHandler(YesHandler)));
dlg.Commands.Add(new UICommand("No", new UICommandInvokedHandler(NoHandler)));
await App.ShowDialog(dlg);

3

我几天前也遇到了同样的问题,解决方法是等待ShowAsync然后进行递归调用,再次打开MessageDialog。

public async void ShowDlg(){
    Action cmdAction = null;
    var msgDlg = new MessageDialog("Content.", "Title");
    msgDlg.Commands.Add(new UICommand("Retry", (x) => {
    cmdAction = () => ShowDlg();
    }));
    msgDlg.Commands.Add(new UICommand("Cancel", (x) => {
    cmdAction = () => <Action associated with the cancel button>;
    }));
    msgDlg.DefaultCommandIndex = 0;
    msgDlg.CancelCommandIndex = 1;

    await msgDlg.ShowAsync();
    cmdAction.Invoke();
}

希望这可以帮助你!

3

1
尝试使用实例变量并保留对asyncCommand的引用,然后检查命令是否不为null。这可能会起作用。 - Syler

1
另一个解决方案:
private bool _messageShowing = false;

// ...

if (!_messageShowing)
{
    _messageShowing = true;
    var messageDialog = new MessageDialog("Example");

    // ... "messageDialog" initialization

    Task<IUICommand> showMessageTask =  messageDialog.ShowAsync().AsTask();
    await showMessageTask.ContinueWith((showAsyncResult) =>
        {
            _messageShowing = false;
        });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接