none
Диалоговое окно при завершении приложения RRS feed

  • Вопрос

  • Здравствуйте! 

    Моё приложение работает со списками, в которые вносятся изменения. Соответственно хотелось бы чтоб при завершении приложения, пользователю задавался вопрос, собирается ли он сохранить изменения, в случае, если он забыл это сделать

    В интернете нашёл способ как вывести диалоговое окно при закрытии пользователем приложения. Но смущает необходимость добавления ограниченных возможностей и использование метода Application.Current.Exit(), который, вроде бы, использовать не рекомендуется

    Может есть другой способ вывода диалогового окна при закрытии приложения?

    1 ноября 2020 г. 22:07

Ответы

  • По совету модератора помечаю свой код как решение, однако оно в некоторых аспектах продиктовано логикой моего приложения. Буду благодарен за замечания, если у кого-то они появятся

    Прочитал ещё одну статью, которая мне помогла

    Повторю, вкратце то, что написано в статьях про добавление  события CloseRequested (Происходит, когда пользователь нажимает системную кнопку для закрытия - кнопка «x» в углу строки заголовка приложения) 
    Важно не забыть добавить соответствующую ограниченную возможность в файл Package.appxmanifest приложения, иначе событие не сработает Переходим к его коду
    1) Добавьте пространство имен в Package.appxmanifest

    xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"

    Чтобы создать пакет приложения без ошибок, нам также необходимо изменить пространство имен, добавив его в  IgnorableNamespaces свойство в Package.appxmanifest

    IgnorableNamespaces="uap mp rescap genTemplate"

    Но в моём манифесте написано так

    IgnorableNamespaces = "uap mp rescap"

    Я ранее добавлял другую ограниченную возможность

    Затем в  Capabilities узле добавьте:
    <rescap:Capability Name="confirmAppClose"/>

    Это Capabilities будет выглядеть так:

    <Capabilities>
    ...
      <rescap:Capability Name="confirmAppClose"/>
    ...
    </Capabilities>

    2) Далее я размещал код с учётом своего приложения.
    Событие добавил прямо в конструктор в code-behind страницы приложения. Она у меня одна 

    SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += LW.CloseRequested;

    LW – ссылка на класс слоя ViewModel, обработчик события, соответственно расположен в этом классе  слоя ViewModel.Там у меня свойство EnSave, указывающее, вносил ли пользователь изменения в список

    public async void CloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
            {
                //Вывод запроса на сохранение списка при закрытии приложения
                _ = sender; //Без этого присваивания Решарпер выводит сообщение -
                //Удалить неиспользуемый параметр "sender"...
                if (EnSave && e != null)
                {
                    var deferral = e.GetDeferral(); // Данная строка должна быть размещена
                    //именно перед методом await subscribeDialog.ShowAsync(),
                    // иначе диалог не выводится и приложение сразу закрывается   
                    ContentDialog subscribeDialog = new ContentDialog
                    {
                        Title = "Сохранить изменения?",
                        Content = "Вы внесли изменения в список",
                        PrimaryButtonText = "Да",
                        SecondaryButtonText = "Нет"
                    };
                    ContentDialogResult result = await subscribeDialog.ShowAsync();
                    if (result == ContentDialogResult.Primary) await mainModel.Save().ConfigureAwait(true);
                    deferral.Complete();
                }
            }

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

    Если нужно дождаться выполнения асинхронного метода, как в данном случае, а не просто запустить его, в заголовке асинхронного метода вместо слова Void пишем Task

    Например

    public async Task Save() // Сохранить
            {
               //код
            }








    2 ноября 2020 г. 18:20

Все ответы

  • Здравствуйте,

    Насколько понимаю вопрос решился? Если да, то впринципе можете Ваше решение вывести в отдельное сообщение и пометить как ответ, тогда люди которые столкнуться с подобной ситуацией смогут легче найти его.


    Если Вам помог чей-либо ответ, пожалуйста, не забывайте жать на кнопку "Предложить как ответ" или "Проголосовать за полезное сообщение" Мнения, высказанные здесь, являются отражение моих личных взглядов, а не позиции корпорации Microsoft. Вся информация предоставляется "как есть" без каких-либо гарантий.

    2 ноября 2020 г. 8:34
    Модератор
  • По совету модератора помечаю свой код как решение, однако оно в некоторых аспектах продиктовано логикой моего приложения. Буду благодарен за замечания, если у кого-то они появятся

    Прочитал ещё одну статью, которая мне помогла

    Повторю, вкратце то, что написано в статьях про добавление  события CloseRequested (Происходит, когда пользователь нажимает системную кнопку для закрытия - кнопка «x» в углу строки заголовка приложения) 
    Важно не забыть добавить соответствующую ограниченную возможность в файл Package.appxmanifest приложения, иначе событие не сработает Переходим к его коду
    1) Добавьте пространство имен в Package.appxmanifest

    xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"

    Чтобы создать пакет приложения без ошибок, нам также необходимо изменить пространство имен, добавив его в  IgnorableNamespaces свойство в Package.appxmanifest

    IgnorableNamespaces="uap mp rescap genTemplate"

    Но в моём манифесте написано так

    IgnorableNamespaces = "uap mp rescap"

    Я ранее добавлял другую ограниченную возможность

    Затем в  Capabilities узле добавьте:
    <rescap:Capability Name="confirmAppClose"/>

    Это Capabilities будет выглядеть так:

    <Capabilities>
    ...
      <rescap:Capability Name="confirmAppClose"/>
    ...
    </Capabilities>

    2) Далее я размещал код с учётом своего приложения.
    Событие добавил прямо в конструктор в code-behind страницы приложения. Она у меня одна 

    SystemNavigationManagerPreview.GetForCurrentView().CloseRequested += LW.CloseRequested;

    LW – ссылка на класс слоя ViewModel, обработчик события, соответственно расположен в этом классе  слоя ViewModel.Там у меня свойство EnSave, указывающее, вносил ли пользователь изменения в список

    public async void CloseRequested(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
            {
                //Вывод запроса на сохранение списка при закрытии приложения
                _ = sender; //Без этого присваивания Решарпер выводит сообщение -
                //Удалить неиспользуемый параметр "sender"...
                if (EnSave && e != null)
                {
                    var deferral = e.GetDeferral(); // Данная строка должна быть размещена
                    //именно перед методом await subscribeDialog.ShowAsync(),
                    // иначе диалог не выводится и приложение сразу закрывается   
                    ContentDialog subscribeDialog = new ContentDialog
                    {
                        Title = "Сохранить изменения?",
                        Content = "Вы внесли изменения в список",
                        PrimaryButtonText = "Да",
                        SecondaryButtonText = "Нет"
                    };
                    ContentDialogResult result = await subscribeDialog.ShowAsync();
                    if (result == ContentDialogResult.Primary) await mainModel.Save().ConfigureAwait(true);
                    deferral.Complete();
                }
            }

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

    Если нужно дождаться выполнения асинхронного метода, как в данном случае, а не просто запустить его, в заголовке асинхронного метода вместо слова Void пишем Task

    Например

    public async Task Save() // Сохранить
            {
               //код
            }








    2 ноября 2020 г. 18:20
  • Здравствуйте,

    Насколько понимаю вопрос решился? Если да, то впринципе можете Ваше решение вывести в отдельное сообщение и пометить как ответ, тогда люди которые столкнуться с подобной ситуацией смогут легче найти его.

    Спасибо! последовал Вашему совету

    2 ноября 2020 г. 18:51
  • И Вам спасибо, что вернулись с решением на форум!

    Если Вам помог чей-либо ответ, пожалуйста, не забывайте жать на кнопку "Предложить как ответ" или "Проголосовать за полезное сообщение" Мнения, высказанные здесь, являются отражение моих личных взглядов, а не позиции корпорации Microsoft. Вся информация предоставляется "как есть" без каких-либо гарантий.

    2 ноября 2020 г. 22:37
    Модератор