2015-03-23 3 views
4

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

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

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

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

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

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

ответ

7

Два 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; 
     } 
    } 
} 
+0

Большое спасибо. Это решило мою проблему и спасло мое здравомыслие! – Qerts

0

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

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

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

EDIT:

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

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

+0

Спасибо, но она действует до сих пор странно, когда я использую его в MainPage конструктор, он работает. Когда я использую его где-нибудь еще, это не так. – Qerts

+0

@Qerts Вы можете опубликовать несколько примеров кода, воспроизводящих вашу проблему. Не портит ли приложение все те же ошибки? –

+0

Я редактировал вопрос с новыми выводами – Qerts