У меня есть форма, которая отображается с помощью 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
}
}
}
Я смущен. Можете ли вы объяснить, почему вам нужно, чтобы немодальное окно вело себя как модальное окно? Похоже, вы должны оставить окно модальным.
Поскольку вы хотите заблокировать выполнение основного интерфейса до тех пор, пока не будет нажата кнопка «ОК» во втором окне, мне кажется, что вам нужно на самом деле модальное окно.
@GabrielLuci Мне нужно иметь возможность нажимать на другие окна за пределами текущего модального окна.
Кстати, у Form
есть свойство DialogResult
— установите его на DialogResult.Ok
, и оно автоматически скроет форму и вернет значение — поэтому ваш код изменится на if (testForm.ShowDialog(this)==DialogResult.Ok)
.
@lzzydy Думаю, это имеет смысл. Затем вам придется переместить код, который должен выполняться после закрытия окна. Любой из двух ответов ниже будет работать.
@lzzydy проверьте мой предложенный ответ с помощью Task
и async-await.
Вы можете обработать событие 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 не вызывается. Как вы думаете, я могу что-то упустить?
вам нужно будет вызвать Close() вместо Hide(), чтобы произошло событие .Closed
@ pm101 Я изменил Hide () на Close (), но событие все еще не происходит.
Хм, я сделал пример проекта, который отлично работает. Можете ли вы обновить свой код по вопросу, чтобы показать нам, что вы делаете нового?
@ pm101 Я обновил код. Я попытался использовать метод в этом комментарии и ниже. У обоих были одинаковые результаты, когда делегата не вызывали.
Самый простой способ — переместить код из 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);
}
Когда я пытаюсь сделать это, я получаю следующую ошибку: «Локальный параметр с именем« отправитель »не может быть объявлен в этой области, потому что это имя используется во внешней локальной области для определения локального или параметра»
Это означает, что во включающем методе уже есть параметр с именем sender
. Я изменил код, чтобы использовать только s и a в качестве имен параметров для делегата, чтобы больше не возникало конфликтов.
Спасибо за разъяснение. С этим изменением кода обработчик событий FormClosed не запускается, когда я нажимаю OK или закрываю форму. Есть ли что-то еще, что я могу пропустить здесь?
Вместо того, чтобы скрывать форму, вы должны закрыть ее. Или вы хотите использовать тот же экземпляр позже снова?
Мне не нужно использовать один и тот же экземпляр. Замена Hide() на Close() также не решает проблему.
Я только что проверил код в тестовом проекте, и делегат был вызван после вызова Close
или использования X для закрытия формы. Так что разница должна быть.
Вы можете использовать обработчик асинхронного события, привязанный к 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();
}
}
Один из способов состоит в том, чтобы диалоговая форма вызывала метод или событие в родительской форме (которое было передано ей в качестве аргумента) при нажатии OkClick.