Страницы

Поиск по вопросам

понедельник, 3 февраля 2020 г.

Метод, ожидающий действие пользователя

#c_sharp #net #wpf #xaml


Пишу WPF-приложение на C#. Есть метод, показывающий окошко с сообщением и 2-мя кнопками.
Он должен возвращать 0 или 1 (например), в зависимости от нажатой кнопки, как это делает
метод ShowDialog() класса Form. Так вот как собственно это реализовать? Вот примерный
макет метода: 

public int ShowMessage()
    {
        OpenWindow();
        //каким-то образом ожидаем действия пользователя
        //отслеживаем нажатую кнопку
        //и возвращаем соответствующее значение
        return (/* if pressedKey1*/) ? 1 : 0;
    } 

    


Ответы

Ответ 1



У Влада какой-то сложный способ, я предлагаю сделать всё просто и топорно. По сути, у диалогов по-хорошему должно быть два способа вызова: модальный и немодальный. Модальный режим предполагает вызов ShowModal, блокировку основного окна и вызывающей функции. Немодальный режим предполагает вызов Show, доступность основного окна и ожидание с помощью await. Использование будет выглядеть так (давайте числа не возвращать, это дурной тон): private async void ShowPopups () { Result modalResult = YesNoPopup.ShowPopupModal("Modal"); // UI блокирован MessageBox.Show(modalResult.ToString()); Result notModalResult = await YesNoPopup.ShowPopup("Not modal"); // UI не блокирован MessageBox.Show(notModalResult.ToString()); } public enum Result { Yes, No, Cancel, } Добавим в класс попапа свойство с результатом вызова, кнопкам назначим соответствующие обработчики. using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using static WpfDialogSample.Result; public class YesNoPopup : Window { private Result? _result; public YesNoPopup () { Button btnYes, btnNo, btnCancel; SizeToContent = SizeToContent.WidthAndHeight; WindowStartupLocation = WindowStartupLocation.CenterScreen; Content = new UniformGrid { Columns = 3, Children = { (btnYes = new Button { Content = "Yes" }), (btnNo = new Button { Content = "No" }), (btnCancel = new Button { Content = "Cancel" }), } }; btnYes.Click += (s, a) => SetResult(Yes); btnNo.Click += (s, a) => SetResult(No); btnCancel.Click += (s, a) => SetResult(Cancel); } private void SetResult (Result result) { _result = result; Close(); } // ... } А дальше в пару строчек реализуем модальную и немодальную версию. Здесь считается, что закрытие диалога эквивалентно нажатию на Cancel. public class YesNoPopup : Window { // ... public static Result ShowPopupModal (string title) { var popup = new YesNoPopup { Title = title }; popup.ShowDialog(); return popup._result ?? Cancel; } public static async Task ShowPopup (string title) { var completion = new TaskCompletionSource(); var popup = new YesNoPopup { Title = title }; popup.Closed += (s, a) => completion.SetResult(popup._result); popup.Show(); return await completion.Task ?? Cancel; } } Собственно, вот и весь код вместе со всеми элементами управления.

Ответ 2



Можно сделать это через через ShowDialog, но мне кажется более чистым метод с async/await. Вот простой вариант: public Task ShowMessage() { var tcs = new TaskCompletionSource(); var w = new YourWindow(); w.Closed += (o, args) => tcs.TrySetResult(w.ClickedButtonIndex) w.Show(); return tcs.Task; } Для этого, понятно, YourWindow должно в публичном свойстве PressedButtonIndex запоминать, какая кнопка была нажата. И закрываться по нажатию любой из кнопок. Это делается так: и в code-behind окна YourWindow void OnButtonClicked(object sender, RoutedEventArgs e) { if (sender == Button1) ClickedButtonIndex = 1; else ClickedButtonIndex = 2; Close(); } public int ClickedButtonIndex { get; private set; } Давайте попробуем более изощрённый вариант Для начала, научимся дожидаться нажатия на кнопку: async Task

Комментариев нет:

Отправить комментарий