C# изучаю не так давно и встала передо мной недавно задача:
— открыть Form2 при нажатии на кнопку в Form1;
— спрятать Form1;
— открыть Form1 при закрытии Form2.
На первый взгляд задача показалась элементарной, но… возникли нюансы — при закрытии приложения оно не выгружалось и в диспетчере задач мы наблюдали его работу, хотя визуально оно как бы закрылось.
В чём же причина такого поведения? Об этом расскажу дальше. Рассмотрим открытие и закрытие форм на примерах.
Открываем и закрываем форму из другой формы
У нас в приложении есть две формы Form1 — главная, которая открывается сразу при запуске приложения и Form2, которую открываем по нажатию на кнопку.
Чтобы открыть Form2 нам необходим следующий код, который будет срабатывать при нажатии на кнопку:
private void button1_Click(object sender, EventArgs e) { Form ifrm = new Form2(); ifrm.Show(); // отображаем Form2 this.Hide(); // скрываем Form1 (this - текущая форма) }
Теперь у нас открылась Form2 и спряталась Form1. Поработав с Form2 мы её закрываем и при этом нам надо после этого отобразить Form1. Многие начинающие, включая меня начинают писать следующий код, который помещаем в событие, которое происходит после закрытия Form2:
private void Form2_FormClosed(object sender, FormClosedEventArgs e) { Form ifrm = new Form1(); ifrm.Show(); // отображаем Form1 this.Close(); // закрываем Form2 (this - текущая форма) // не используйте данный способ, правильный ниже }
Вроде всё логично: Form2 закрылась, Form1 открылась. Однако используя этот метод, мы можем заметить, что после того как мы закрываем приложение оно продолжает висеть в памяти. Многие, не зная почему это происходит дописывают в метод «Form1_FormClosed» дописывают принудительное закрытие приложения:
Application.Exit();
Это работает, однако правильно ли это? Решать вам.
А теперь ответим на вопрос «почему приложение висит в памяти» и рассмотрим простое и правильное решение.
Первая часть кода: мы отображаем Form2 и скрываем Form1. Не закрываем, а именно скрываем, т.е. экземпляр Form1 продолжает существовать.
Закрыть Form1 вместо скрытия не получится, так как это главная форма приложения и при её закрытии мы закроем всё приложение.
Вторая часть кода: строкой «Form ifrm = new Form1();» мы создаём второй экземпляр Form1 и далее его и отображаем, а первый экземпляр Form1 продолжает жить в памяти. И когда мы закрываем приложение (Form1), то первый экземпляр при этом не закрываем он так и «сидит» в памяти, поэтому приложение не выгружается из памяти. В связи с этим многие и закрывают принудительно приложение при закрытии главной формы (Form1).
Сейчас мы с вами рассмотрим правильный код, который не будет создавать второй экземпляр Form1 и отображать его, а будет отображать скрытую до этого Form1.
private void Form2_FormClosed(object sender, FormClosedEventArgs e) { // вызываем главную форму приложения, которая открыла текущую форму Form2, главная форма всегда = 0 Form ifrm = Application.OpenForms[0]; ifrm.Show(); }
OpenForms — получает коллекцию открытых форм приложения. В нашем случае мы сразу обратились к главной форме приложения (OpenForms[0]).
Теперь при закрытии Form2 у нас будет вызываться и отображаться та форма, которая породила закрывающуюся.
Учитываем координаты форм при открытии
Представьте ситуацию. Открыта Form1 вы её перемещаете в правый верхний угол экрана. Потом нажимаете на кнопку и… Form2 открывается по центру экрана или в другом месте, но не в том месте, где была Form1. Многие улыбнуться и скажут, что в свойствах Form2 надо прописать/указать следующее «StartPosition -> CenterParent» и открывать Form2 следующим методом:
Form ifrm = new Form2();
ifrm.ShowDialog();
Это правильное решение, которое всегда будет открывать Form2 поверх Form1 и всегда по центру Form1. Однако этот код не применим, если вам надо скрывать Form1, так как Form1 не будет скрываться.
Сейчас приведу полное решение, которое позволит открывать Form1 и Form2 в той же точке, где находилась до этого форма, вызывающая другую форму. Код включает всё вышеописанное. В свойствах форм надо прописать следующее (прямо в студии выбираете эти значения):
— свойство Form1: «StartPosition -> CenterScreen»
— свойство Form2: «StartPosition -> Manual»
Код в Form1:
private void button1_Click(object sender, EventArgs e) { Form ifrm = new Form2(); ifrm.Left = this.Left; // задаём открываемой форме позицию слева равную позиции текущей формы ifrm.Top = this.Top; // задаём открываемой форме позицию сверху равную позиции текущей формы ifrm.Show(); // отображаем Form2 this.Hide(); // скрываем Form1 (this - текущая форма) }
Код в Form2:
private void Form2_FormClosed(object sender, FormClosedEventArgs e) { // вызываем главную форму, которая открыла текущую, главная форма всегда = 0 - [0] Form ifrm = Application.OpenForms[0]; ifrm.StartPosition = FormStartPosition.Manual; // меняем параметр StartPosition у Form1, иначе она будет использовать тот, который у неё прописан в настройках и всегда будет открываться по центру экрана ifrm.Left = this.Left; // задаём открываемой форме позицию слева равную позиции текущей формы ifrm.Top = this.Top; // задаём открываемой форме позицию сверху равную позиции текущей формы ifrm.Show(); // отображаем Form1 }
Теперь вы не создаёте второго экземпляра Form1 и приложение всегда будет закрываться, не оставаясь в памяти.
Открываем форму поверх другой формы, как модальное окно
Чтобы открыть Form2 поверх Form1, как модальное окно, не скрывая Form1, вам хватит этого кода:
private void button1_Click(object sender, EventArgs e) { Form ifrm = new Form2(); ifrm.ShowDialog(); }
В итоге Form2 будет открыта поверх Form1. В этом случае пользователь не сможет переключиться на Form1 не закрыв Form2.
На этом всё.
Спасибо!
Спасибо.
Очень подробные и одновременно краткие уроки.
Спасибо, очень помог совет
Как сделать чтобы при нажатие на кнопку в формы один нажималась кнопка в форме 2 c#
Через делегаты пробуй.
Спасибо!
Эта штука не работает. Когда получаешь коллекцию открытых форм из второй формы, то там находится одна единственная вторая форма под индексом 0..
Application.OpenForms[0]
Тут важную роль играет Application, таким образом ты получаешь коллекцию форм всего приложения.
Отлично, спасибо!
Супер! Спасибо за ликбез!
У меня тоже не работает.
Отдуши спассииибо, суперский помог. Насчет объяснения нет слов, супер. Все четко, простыми словами, коротко и ясно.