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.
На этом всё.
Отличная статья, как раз решило мою идентичную проблему, автору удачи в дальнейшем и спасибо за помощь!!!
вроде стать о том как с одной формы закрыть другу?! причем тут скрытие/закрытие первой открытия второй и на оборот????
Ответ в статье.
А если форм 4? Я пробовал вписать в каждые 3 код из примера ‘Form 2’ и ничего. Можете подсказать что нужно поменять?
Что конкретно не получается у вас и что вы хотите делать?
Вы используете wpf или winform?
winform. У меня 4 формы. и хочу чтобы все остальные открывались в таком же расположении что и первая(главная). Я новичок и не совсем понял что именно Демьян имел ввиду. Мне нужно OpenForms[0] и в нем менять значение под каждую форму?
Если надо открывать очередную форму в том же месте, в котором открыта форма из которой вызываем новую форму, то перед тем как открыть очередную форму, надо задать ей координаты.
Пишем код в нужном месте:
Form ifrm = new Form2(); // Form2 заменяем на ту форму, которую вызываем Form3, Form4…
ifrm.Left = this.Left; // задаём новой форме позицию слева
ifrm.Top = this.Top; // задаём новой форме позицию сверху
ifrm.Show(); // отображаем форму
this.Hide(); // скрываем текущую форму
this.Left, this.Top используем только если открытая форма и новая открываемая форма одинаковые по размеру, иначе надо высчитывать позицию слева и сверху.
Демьян выше писал:
Application.OpenForms[0]
Тут важную роль играет Application, таким образом ты получаешь коллекцию форм всего приложения.
Отдуши спассииибо, суперский помог. Насчет объяснения нет слов, супер. Все четко, простыми словами, коротко и ясно.
У меня тоже не работает.
Супер! Спасибо за ликбез!
Отлично, спасибо!
Эта штука не работает. Когда получаешь коллекцию открытых форм из второй формы, то там находится одна единственная вторая форма под индексом 0..
Application.OpenForms[0]
Тут важную роль играет Application, таким образом ты получаешь коллекцию форм всего приложения.
Спасибо!
Как сделать чтобы при нажатие на кнопку в формы один нажималась кнопка в форме 2 c#
Через делегаты пробуй.
Спасибо, очень помог совет
Спасибо.
Очень подробные и одновременно краткие уроки.
Спасибо!