Многократный сбой приложения MessageDialog

Я использую MessageDialogues в нескольких местах над моим приложением. Проблема в том, что когда-либо MessageDialog (или системное оповещение, например предупреждение о возможностях), активен и другой MessageDialog приложение вылетает без исключения или с UnathorizedAccessException,

Вот как я называю MessageDialog:

CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    MessageDialog msg2 = new MessageDialog(_resourceLoader.GetString("MsgGPSUnavailable"));
    msg2.ShowAsync();
});

Я думал, что я должен ждать закрытия диалога, но с помощью Dispatcher Я помещаю это диалоговое окно в основной поток пользовательского интерфейса, который обрабатывает это сам или нет? Спасибо за любое объяснение этой проблемы.

Редактировать - я продолжил шаг за шагом и получил следующий код, который содержится в том же классе. Когда я запускаю приложение, вызывается LoadDataToModel. Это нормально, и диалог отображается как msgGPSDisabled. После этого происходит событие и вызывается locator_StatusChanged. Это тоже нормально, и диалог отображается. Теперь странная часть. Когда я не вызываю msgGPSDisabled в LoadDataToModel и только в locator_StatusChanged, приложение вылетает сразу после отображения диалога. Нет исключений, и App.gics открывается в строке 47 (DEBUG &&!DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION). Даже если я использую try-catch везде, где это возможно. Когда я использую msgGPSDisabled без Dispatcher в locator_StatusChanged, возникают исключения. Не ловится, "предмет не найден"

public async Task LoadDataToModel()
{
    await msgGPSDisabled();

    this.IsBusy = true;

    await LoadDataGarvis(Stations); //rozparsuje raw data a načte je do modelu
    InitializePins();

    this.IsBusy = false;


    }

void locator_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
{
    switch (sender.LocationStatus)
    {
        case Windows.Devices.Geolocation.PositionStatus.Disabled:

            try
            {
                CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
                {
                    await msgGPSDisabled();
                    IsGPSBusy = false;
                    IsGPS = false;

                });
            }
            catch (UnauthorizedAccessException)
            {
                 throw;
            }
            catch (Exception) {throw; }

        case Windows.Devices.Geolocation.PositionStatus.NoData:
            CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
            {
                await msgGPSUnavailable();
            });

        }
    }


private async Task msgGPSDisabled()
{
    MessageDialog sss = new MessageDialog(_resourceLoader.GetString("MsgGPSDisabled"));
    await sss.ShowAsync();
}

2 ответа

Решение

Два MessageDialogs не может быть отображено в то же время. У вас есть несколько вариантов, если вы хотите продолжить использовать MessageDialogs и для всех было бы лучше иметь какую-то MessageDialogService управлять вызовами для вызова диалогов:

  • Закройте существующий диалог, когда вам нужно открыть новый. Это самый простой и, возможно, лучший вариант, хотя вы рискуете отменить диалог, который может быть как-то важным в зависимости от того, о чем ваши диалоги.
  • Поставьте в очередь диалоги, чтобы старые не удалялись, а новые показывались после того, как старые были уволены. Этот будет гарантировать, что все диалоги закрыты пользователем, но это может быть проблемой, если ваше приложение может как-то начать показывать сотни диалогов.
  • Открывайте только новую, если она еще не отображена. Теперь это рискует, что более новое сообщение не отображается, что звучит более проблематично, чем первый вариант.

Если вы хотите использовать опцию очереди - вы можете использовать этот код:

using System;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Popups;
using Windows.UI.Xaml;

namespace WinRTXamlToolkit.Controls.Extensions
{
    /// <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<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;
        }
    }
}

Ваша лямбда все еще должна ожидать асинхронного вызова, так что когда диспетчер ее запустит, он не продолжится, пока окно сообщения не закроется.

Я не пробовал, но это должно помочь (обратите внимание на использование async а также await ключевые слова):

CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
    MessageDialog msg2 = new MessageDialog(_resourceLoader.GetString("MsgGPSUnavailable"));
    await msg2.ShowAsync();
});

РЕДАКТИРОВАТЬ:

Как уже объяснил Филипп, вы не можете одновременно отображать более одного окна сообщения. Он также предложил несколько подходов, которые вы могли бы использовать, чтобы избежать проблемы.

В вашем сценарии (сообщающем об изменениях статуса GPS), возможно, было бы лучше отобразить статус в виде метки внутри вашего пользовательского интерфейса, поскольку вам не нужно, чтобы пользователь каким-либо образом реагировал на него. Вы даже можете собирать значения по мере их изменения в списке и отображать их, используя ItemsControl чтобы пользователь мог наблюдать историю изменений (возможно, с отметкой времени). Все зависит от того, чего вы хотите достичь.

Другие вопросы по тегам