Как предотвратить появление нескольких диалоговых окон подтверждения при закрытии форм в приложении WinForms?

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

protected override void OnFormClosing(FormClosingEventArgs e)
{
    if (e.CloseReason == CloseReason.UserClosing)
    {
        DialogResult result = MessageBox.Show("Are you sure you want to close the application?", "Confirm Exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

        if (result == DialogResult.No)
        {
            e.Cancel = true; // Cancel the form closing
            return;
        }
        else
        {
            // Close the entire application
            Application.Exit();
        }
    }
}

Это диалоговое окно появляется два или более при закрытии приложения.

  • Как я могу гарантировать, что диалоговое окно подтверждения отображается только один раз при закрытии формы?

  • Есть ли более эффективный способ закрытия нескольких форм и отображения диалогового окна подтверждения только один раз?

  • Диалоговое окно подтверждения предназначено для подтверждения того, хочет ли пользователь закрыть все приложение.

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

Это форма администратора сайта, вызывающая все диалоговые окна подтверждения, или диалоги происходят из нескольких разных форм?

Mustafa Özçetin 28.08.2024 08:46

нам нужно знать, где находится размещенный код (в какой форме) и связь между всеми различными открытыми формами (какая форма какую открывает)

Mong Zhu 28.08.2024 08:49

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

vhr 28.08.2024 08:50

Сначала я пропустил ссылку на ваше изображение, но когда я ее преобразовал, понял, что здесь может быть задействован вход в систему. Таким образом, в дополнение к общему случаю, описанному в моем ответе ниже, эти ответы «может или не может» дают дополнительную ясность относительно уникальных проблем, которые возникают, когда вы показываете логин или заставку до отображения основной формы: stackoverflow.com/a /75534137/5438626 stackoverflow.com/a/74736871/5438626

IV. 28.08.2024 17:30
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
64
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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


Таким образом, вы можете поэкспериментировать с упрощением MainForm.OnFormClosing(), которое будет вызываться «любым» Application.Exit вызовом из любого места кода. Здесь не должно быть никакой необходимости проверять CloseReason, и, передав this в Show(this), это гарантирует, что дочерние формы останутся поверх основной формы в Z-порядке и удалятся, когда MainForm это сделает (как запишет отладочная запись ). Чтобы уточнить это, нет необходимости вызывать ApplicationExit() здесь, потому что, если закрывается основная форма, а подсказка не отменяет ее, приложение закроется.

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();            
        buttonShowFormA.Click += (sender, e) => _formA.Show(this);
        buttonShowFormB.Click += (sender, e) => _formB.Show(this);
        _formA.VisibleChanged += (sender, e) => buttonShowFormA.Enabled = !_formA.Visible;
        _formB.VisibleChanged += (sender, e) => buttonShowFormB.Enabled = !_formB.Visible;
#if DEBUG
        _formA.Disposed += (sender, e) => Debug.WriteLine("Disposing Form A");
        _formB.Disposed += (sender, e) => Debug.WriteLine("Disposing Form B");
#endif
    }
    ChildFormA _formA = new() { StartPosition = FormStartPosition.Manual };
    ChildFormB _formB = new () { StartPosition = FormStartPosition.Manual };
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        _formA.Location = new() { X = Right + 10, Y = Top };
        _formB.Location = new() { X = Right + 10, Y = Top + _formA.Height + 10 };
        _formA.Show(this);
        _formB.Show(this);
    }
    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        base.OnFormClosing(e);
        DialogResult result = MessageBox.Show("Are you sure you want to close the application?", "Confirm Exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

        if (result == DialogResult.No)
        {
            e.Cancel = true; // Cancel the form closing
            return;
        }
    }
}

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

Распространенный способ справиться с этим — отменить Close и вместо этого преобразовать его в форму Hide, разрешая только Close продолжить работу, это выход CloseReason is из приложения или какое-либо другое завершение работы системы.

public partial class ChildFormA : Form
{
    public ChildFormA()
    {
        InitializeComponent();
        buttonClose.Click += (sender, e) => Close();
        buttonExit.Click += (sender, e) => Application.Exit();
    }
    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        base.OnFormClosing(e);
        switch (e.CloseReason)
        {
            case CloseReason.UserClosing:
                e.Cancel = true;
                Hide();
                break;
        }
    }
}

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

Вот код, который я использовал для проверки этого ответа, если это поможет. Клон

IV. 28.08.2024 16:50
Ответ принят как подходящий

Я попытался воссоздать проблему, и ваш код работает отлично. Думаю, проблема в другом. Была ли форма входа в систему вашей формой запуска (основной)?

вот код, который совпадает с вашим, однако я пропустил

Application.Exit();

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

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

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        if (e.CloseReason == CloseReason.UserClosing)
        {
            DialogResult result = MessageBox.Show("Are you sure you want to close the application?", "Confirm Exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

            if (result == DialogResult.No)
            {
                e.Cancel = true; // Cancel the form closing
                return;
            }
        }
    }
}

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