Многократный сбой приложения 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
чтобы пользователь мог наблюдать историю изменений (возможно, с отметкой времени). Все зависит от того, чего вы хотите достичь.