Замена ShowDialog() на Show()

У меня есть форма, которая отображается с помощью ShowDialog(), поэтому это модальное окно.

private void OpenForm(object sender, ItemClickEventArgs e)
{
    MyForm testForm = new MyForm();
    ...
    testForm.Enabled = true;
    testForm.ShowDialog(this);
    var dialogOk = testForm.DialogOK;
    if (dialogOk)
    {
       //do some stuff 1
    }
}

На форме есть кнопка «ОК». При нажатии кнопки «ОК» DialogOk устанавливается в значение «истина». Внутри класса MyForm:

private void OkClick(object sender, EventArgs e)
{
   // do some stuff 2
   ... 
   DialogOK = true;
   Hide();
}

Мне нужно преобразовать это в немодальное окно. Кажется, решение состоит в том, чтобы использовать Show() вместо ShowDialog(), но когда я использую Show(), код не останавливается и не ждет нажатия кнопки OK, поэтому «сделать что-то 1» никогда не вызывается.

Используя Show (), как я могу сохранить поведение, чтобы «сделать что-то 1» запускалось после нажатия кнопки «ОК»?

Обновление: вот что я сейчас пытаюсь:

public partial class MyForm: XtraForm
{
   public bool DialogOk;

   private void OkClick(object sender, EventArgs e)
   {
      // do some stuff 2
      ... 
      DialogOk = true;
      Close();
   }
}

Способ 1:

public partial class MyMainForm : XtraForm
{
   private MyForm testForm;

   private void OpenForm(object sender, ItemClickEventArgs e)
    {
        if (testForm == null)
        {
            testForm = new MyForm();
        }
        ...
        testForm.Enabled = true;
        testForm.FormClosed += (s, a) => {
            var dialogOk = testForm.DialogOk;
            if (dialogOk)
            {
                // do some stuff 1
            }
        };
        testForm.Show(this);
    }
}

Способ 2:

public partial class MyMainForm : XtraForm
{
       private MyForm testForm;

       private void OpenForm(object sender, ItemClickEventArgs e)
        {
            if (testForm == null)
            {
                testForm = new MyForm();
            }
            ...
            testForm.FormClosed += testForm_Closed;
            testForm.Show(this);
        }

        private void testForm_Closed(object sender, EventArgs args)
        {
            var testForm = (Form)sender;
            testForm.Closed -= testForm_Closed;

            if (testForm.DialogResult == DialogResult.OK)
            {
               // do some stuff 1
            }
        }
 }

Один из способов состоит в том, чтобы диалоговая форма вызывала метод или событие в родительской форме (которое было передано ей в качестве аргумента) при нажатии OkClick.

Alex K. 31.01.2019 16:04

Я смущен. Можете ли вы объяснить, почему вам нужно, чтобы немодальное окно вело себя как модальное окно? Похоже, вы должны оставить окно модальным.

Gabriel Luci 31.01.2019 16:04

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

meJustAndrew 31.01.2019 16:05

@GabrielLuci Мне нужно иметь возможность нажимать на другие окна за пределами текущего модального окна.

lzdyzydy 31.01.2019 16:07

Кстати, у Form есть свойство DialogResult — установите его на DialogResult.Ok, и оно автоматически скроет форму и вернет значение — поэтому ваш код изменится на if (testForm.ShowDialog(this)==DialogResult.Ok).

Zohar Peled 31.01.2019 16:08

@lzzydy Думаю, это имеет смысл. Затем вам придется переместить код, который должен выполняться после закрытия окна. Любой из двух ответов ниже будет работать.

Gabriel Luci 31.01.2019 16:13

@lzzydy проверьте мой предложенный ответ с помощью Task и async-await.

Nkosi 31.01.2019 19:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
7
413
4

Ответы 4

Вы можете обработать событие Form.Closed:

MyForm testForm = new MyForm();
testForm.Closed += testForm_Closed;
testForm.Show();

private void testForm_Closed(object sender, EventArgs args)
{
    var testForm = (Form)sender;
    testForm.Closed -= testForm_Closed;

    if (testForm.DialogResult == OK)
        // do some stuff 1
}

Когда я нажимаю OK в форме, OkClick() все еще вызывается, но testForm_Closed не вызывается. Как вы думаете, я могу что-то упустить?

lzdyzydy 31.01.2019 16:50

вам нужно будет вызвать Close() вместо Hide(), чтобы произошло событие .Closed

pm101 31.01.2019 17:05

@ pm101 Я изменил Hide () на Close (), но событие все еще не происходит.

lzdyzydy 31.01.2019 17:15

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

pm101 31.01.2019 17:26

@ pm101 Я обновил код. Я попытался использовать метод в этом комментарии и ниже. У обоих были одинаковые результаты, когда делегата не вызывали.

lzdyzydy 31.01.2019 18:01

Самый простой способ — переместить код из OpenForm в обработчик событий OkClick. Однако, если это не лучшее место для размещения кода, потому что вы можете использовать одну и ту же форму для разных задач, вы можете добавить обработчик события FormClosed, который вызывается после закрытия формы и запускает код, например :

private void OpenForm(object sender, ItemClickEventArgs e)
{
    MyForm testForm = new MyForm();
    ...
    testForm.Enabled = true;
    testForm.FormClosed += (s, a) => {
      var dialogOk = testForm.DialogOK;
      if (dialogOk)
      {
         //do some stuff 1
      }
    };
    testForm.Show(this);
}

Когда я пытаюсь сделать это, я получаю следующую ошибку: «Локальный параметр с именем« отправитель »не может быть объявлен в этой области, потому что это имя используется во внешней локальной области для определения локального или параметра»

lzdyzydy 31.01.2019 16:22

Это означает, что во включающем методе уже есть параметр с именем sender. Я изменил код, чтобы использовать только s и a в качестве имен параметров для делегата, чтобы больше не возникало конфликтов.

Markus 31.01.2019 16:27

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

lzdyzydy 31.01.2019 16:52

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

Markus 31.01.2019 16:57

Мне не нужно использовать один и тот же экземпляр. Замена Hide() на Close() также не решает проблему.

lzdyzydy 31.01.2019 17:07

Я только что проверил код в тестовом проекте, и делегат был вызван после вызова Close или использования X для закрытия формы. Так что разница должна быть.

Markus 31.01.2019 17:27

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

private asyc void OpenForm(object sender, ItemClickEventArgs e) {
    var source = new TaskCompletionSource<DialogResult>();

    EventHandler handler = null;
    handler = (s, args) => { 
        var  form = (MyForm)s;
        form.FormClosed -= handler;
        source.SetResult(form.DialogResult);
    }

    var testForm = new MyForm();
    testForm.FormClosed += handler; //subscribe
    //...
    testForm.Enabled = true;
    testForm.Show();

    var dialogOk = await source.Task;
    if (dialogOk == DialogResult.Ok) {
       //do some stuff 1
    }
}

При этом вы можете сохранить логику в OpenForm и позволить коду ждать без блокировки.

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

public partial class MyForm: XtraForm {

    //...

    private void OkClick(object sender, EventArgs e) {
        // do some stuff 2
        // ... 

        DialogResult = DialogResult.Ok;
        Cose();
    }
}

Это работает для меня, так что не уверен, почему это не для вас (почесывая голову)... Эта форма имеет две кнопки, одна из которых снова открывает ту же форму, а другая кнопка закрывает форму. Родительская форма добавляет событие к закрытому событию.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Form1 test = new Form1();

        test.FormClosed += Test_FormClosed;

        test.Show();
    }

    private void Test_FormClosed(object sender, FormClosedEventArgs e)
    {
        MessageBox.Show("closed -- do something else here!");
    }

    private void button2_Click(object sender, EventArgs e)
    {
        Close();
    }
}

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