Как закрыть одну форму и открыть другую в c
Перейти к содержимому

Как закрыть одну форму и открыть другую в c

  • автор:

Как открыть и закрыть форму из другой формы в C# (правильное решение)

C# изучаю не так давно и встала передо мной недавно задача:
— открыть Form2 при нажатии на кнопку в Form1;
— спрятать Form1;
— открыть Form1 при закрытии Form2.
На первый взгляд задача показалась элементарной, но… возникли нюансы — при закрытии приложения оно не выгружалось и в диспетчере задач мы наблюдали его работу, хотя визуально оно как бы закрылось.

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

Открываем и закрываем форму из другой формы

У нас в приложении есть две формы Form1 — главная, которая открывается сразу при запуске приложения и Form2, которую открываем по нажатию на кнопку.

Чтобы открыть Form2 нам необходим следующий код, который будет срабатывать при нажатии на кнопку:

Теперь у нас открылась Form2 и спряталась Form1. Поработав с Form2 мы её закрываем и при этом нам надо после этого отобразить Form1. Многие начинающие, включая меня начинают писать следующий код, который помещаем в событие, которое происходит после закрытия Form2:

Вроде всё логично: Form2 закрылась, Form1 открылась. Однако используя этот метод, мы можем заметить, что после того как мы закрываем приложение оно продолжает висеть в памяти. Многие, не зная почему это происходит дописывают в метод «Form1_FormClosed» дописывают принудительное закрытие приложения:

Это работает, однако правильно ли это? Решать вам.

А теперь ответим на вопрос «почему приложение висит в памяти» и рассмотрим простое и правильное решение.

Первая часть кода: мы отображаем Form2 и скрываем Form1. Не закрываем, а именно скрываем, т.е. экземпляр Form1 продолжает существовать.

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

Вторая часть кода: строкой «Form ifrm = new Form1();» мы создаём второй экземпляр Form1 и далее его и отображаем, а первый экземпляр Form1 продолжает жить в памяти. И когда мы закрываем приложение (Form1), то первый экземпляр при этом не закрываем он так и «сидит» в памяти, поэтому приложение не выгружается из памяти. В связи с этим многие и закрывают принудительно приложение при закрытии главной формы (Form1).

Сейчас мы с вами рассмотрим правильный код, который не будет создавать второй экземпляр Form1 и отображать его, а будет отображать скрытую до этого Form1.

OpenForms — получает коллекцию открытых форм приложения. В нашем случае мы сразу обратились к главной форме приложения (OpenForms[0]).

Теперь при закрытии Form2 у нас будет вызываться и отображаться та форма, которая породила закрывающуюся.

Учитываем координаты форм при открытии

Представьте ситуацию. Открыта Form1 вы её перемещаете в правый верхний угол экрана. Потом нажимаете на кнопку и… Form2 открывается по центру экрана или в другом месте, но не в том месте, где была Form1. Многие улыбнуться и скажут, что в свойствах Form2 надо прописать/указать следующее «StartPosition -> CenterParent» и открывать Form2 следующим методом:

Это правильное решение, которое всегда будет открывать Form2 поверх Form1 и всегда по центру Form1. Однако этот код не применим, если вам надо скрывать Form1, так как Form1 не будет скрываться.

Сейчас приведу полное решение, которое позволит открывать Form1 и Form2 в той же точке, где находилась до этого форма, вызывающая другую форму. Код включает всё вышеописанное. В свойствах форм надо прописать следующее (прямо в студии выбираете эти значения):

— свойство Form1: «StartPosition -> CenterScreen»
— свойство Form2: «StartPosition -> Manual»

Открыть и закрыть форму из другой формы в C# (правильное решение)

Теперь вы не создаёте второго экземпляра Form1 и приложение всегда будет закрываться, не оставаясь в памяти.

Открываем форму поверх другой формы, как модальное окно

Чтобы открыть Form2 поверх Form1, как модальное окно, не скрывая Form1, вам хватит этого кода:

В итоге Form2 будет открыта поверх Form1. В этом случае пользователь не сможет переключиться на Form1 не закрыв Form2.

Закрыть Form1, открыть Form2

Да-да-да, понимаю, тема «заезжая», но сколько я не рыл, ни где толком не объясняется почему все скрывают/показывают форму так:

Таким способом, активная форма не закрывается, а скрывается, правильно?

Как правильно закрыть Form1 и открыть Form2 ?

SVE's user avatar

Максим's user avatar

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

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

Если первая форма в дальнейшем не используется, то можно использовать 2 варианта:

1. Правим Program.cs

По умолчанию содержимое файла Program.cs выглядит так:

Как вы можете заметить, Form1 запускается как приложение и, при завершении работы формы, произойдет выход из Main и приложения.

Чтобы этого не произошло, можно прописать последовательность запуска форм:

Тогда при закрытии первой формы, будет вызвана вторая и так до последней.

Недостаток — сложно передавать данные между формами. Да можно определить поля в классе Program , конструкторы с параметрами в формах и передавать данные через эти поля и параметры конструкторов, но что делать если нужно вернуться в одну из предыдущих форм? Пилить сложную логику переходов в Main — не сама лучшая идея, мягко говоря.

2. Переходим от форм к контролам

В WinForms есть замечательный класс UserControl. Это фактически пустой контрол, который вы можете наполнить любым содержимым как и форму.

После того, как набор таких контролов подготовлен, вам остается только разместить их на форме с параметром Dock = DockStyle.Fill и управляя значением свойства Conrol.Visible , показывать тот контрол, который вам нужен в данный момент. Если не хотите держать контрол в памяти, ни кто не мешает просто создавать его в нужный момент и отображать, а после использования и переключения на новый контрол, отписаться от событий, вызвать Dispose() , удалить все ссылки и отдать его на растерзание сборщику мусора. Только выигрыш от этого невелик, особенно если вдруг надумаете снова его показать.

Забыл написать про еще один недостаток переключения между формами через Main . Каждая новая форма будет открываться немного в другом месте, может для защиты от программ-автокликеров это и хорошо, но меня, как пользователя, такое поведение раздражает, и думаю что не только меня.

Ещё можно не передавать форму в Application.Run и запустить его без параметров. Тогда даже закрытие всех форм не приведёт к закрытию приложения. Чтобы выйти окончательно необходимо будет вызвать Application.Exit – Lunar Whisper

Тоже хороший вариант, если необходимо использовать разные формы в процессе работы.

c # открыть новую форму, а затем закрыть текущую форму?

Например, предположим, что я нахожусь в форме 1, тогда я хочу:

  1. Открыть форму 2 (с кнопки в форме 1)
  2. Закрыть форму 1
  3. Сосредоточьтесь на форме 2

Ужасное удобство использования. Если вы используете WinForms, просто создайте окно контейнера и замените вместо него панели. Ваши пользователи будут любить вас за это (и ненавидеть за то, что вы этого не делаете) — Claus Jørgensen

Слушай Клауса! Возможно, вы пытаетесь достичь: a) Winforms-реализация последовательной серии шагов, подобной мастеру, или b) попытка показать форму «результат» после формы «ввод / отправка данных». Независимо от того, а) или б) поведение пользовательского интерфейса, которое вы пытаетесь реализовать, является неоптимальным решением. — Simen S

Большое спасибо Clause и Simen S. Ваши комментарии очень полезны для такого новичка, как я. Я прочитаю больше руководств по графическому интерфейсу и удобству использования. Не могли бы вы порекомендовать мне несколько полезных? — tnhan07

Отметьте также [ответы здесь] (stackoverflow.com/questions/4759334/…), если вы действительно намеревались иметь форму входа (или аналогичную). — ilias iliadis

15 ответы

Решение Стива не работает. При вызове this.Close () текущая форма удаляется вместе с form2. Поэтому вам нужно скрыть его и установить событие form2.Closed для вызова this.Close ().

в формах окон в точечной сети нет события Closed. Можете ли вы сказать мне, что это событие FormClosed — Анджали

Разве скрытие первой формы не сохраняет ее в памяти? Как мы можем освободить этот ресурс? — user2635088

form2.Closed += (s, args) => this.Close(); Могу я узнать, как работает это заявление? что именно (s,args) является? — Яш Сарайя

(s, args) => this.Close(); является лямбда-выражением. Он создает функцию «на месте», которая вызывается, когда form2.Closed событие запущено. (s, args) это просто имена параметров лямбда. Что для обработчика событий обычно выглядит примерно так: (object sender, EventArgs e) . Потому что Closed подпись делегата события описывает их типы, типы не указаны (кто-нибудь, пожалуйста, исправьте мою формулировку, если нужно). // В целом это просто хитрый способ не объявлять всю функцию (обработчик событий) за пределами текущей, которая обрабатывает Form2.Closed мероприятие. — КДекер

он просто скрывает первую форму и открывает новую форму, но не закрывает первую форму — Уддян Семвал

В других ответах уже описано много разных способов. Однако многие из них либо участвовали ShowDialog() или, что form1 оставайтесь открытыми, но скрытыми. На мой взгляд, лучший и интуитивно понятный способ — просто закрыть form1 а затем создать form2 из внешнего местоположения (то есть не изнутри любой из этих форм). В случае, когда form1 был создан в Main , form2 можно просто создать с помощью Application.Run как form1 перед. Вот пример сценария:

Мне нужно, чтобы пользователь ввел свои учетные данные, чтобы я как-то их аутентифицировал. Впоследствии, если аутентификация прошла успешно, я хочу показать пользователю главное приложение. Для этого я использую две формы: LogingForm и MainForm , LoginForm имеет флаг, определяющий, была ли аутентификация успешной или нет. Затем этот флаг используется, чтобы решить, создавать ли MainForm экземпляр или нет. Ни одна из этих форм не должна знать о другой, и обе формы можно изящно открывать и закрывать. Вот код для этого:

ответ дан 14 апр.

Это приятный трюк, чем сокрытие форм. Когда у нас есть скрытые формы для выхода из приложения, недостаточно просто закрыть текущую форму. Мы должны использовать Application.Exit (0) и т. Д. — Пек_коньон

Приятно, но мне кажется, подходит только для 2-х форм. А как насчет переключения между несколькими формами ?? — Доктор МАФ

Как закрыть главную форму при открытии дочерней?

Обработчик кнопки главной формы которая открывает дочернее окно.

Конструктор дочерней формы

В итоге закрываются обе формы при открытии дочерней.

Ответы (2 шт):

Это зависит от того, как запущено ваше приложение. Если ваше приложение просто ожидает закрытия главной формы — то когда вы её закрываете, происходит выход из приложения, при этом закрываются все остальные формы.

Да и смысл закрывать основную форму? Вы больше к ней не планируете возвращаться?

Если таки вам надо основную форму убрать с экрана, вы можете её скрыть, например, так

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

Если в Visual Studio создать новый WinForms проект и посмотреть код в файле Program.cs, можно увидеть что приложение запускается вот такой строчкой:

Этот код неявно создает новый экземпляр ApplicationContext, который подписывается у переданной формы на событие FormClosed. Когда возникает событие FormClosed , ApplicationContext вызывает метод Application.ExitThread, который закрывает все окна и завершает приложение.

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

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

Теперь главное только следить за тем, чтобы у пользователя была возможность закрыть все формы. Нельзя допускать чтобы последняя форма не имела кнопки в правом верхнем углу и не обрабатывала Alt+F4.

Однако, если применить описанный выше подход в вашем примере, он все равно не сработает.

Вы закрываете вызывающую форму в конструкторе дочерней. В этот момент дочерняя форма все еще не открыта, и Application.OpenForms окажется пустым, что приведет к завершению приложения.

Можно перенести код, закрывающий вызывающую форму в метод OnShown .

А проще сделать так, чтобы вызывающая форма закрывала сама себя.

Метод ShowDialog открывает модальное окно. Оно зависит от родительского окна, и закрывается вместе с ним. Если вызывающая форма это единственное открытое окно на данный момент, она автоматически становится родительской для Form2 . Для того, чтобы разорвать связь с вызывающей формой, показывайте Form2 с помощью метода Show.

Бонус

В описанном сценарии, вам наверняка нет нужды, чтобы форма, которую вы показали первоначально, оставалась висеть в памяти после ее закрытия. Однако, Form1 это локальная переменная метода Main . Ссылка на Form1 будет хранится на стеке до тех пор, пока приложение не завершатся.

Чтобы не создавать локальную переменную, можно изменить MyApplicationContext таким образом, что он будет самостоятельно создавать самую первую форму в своем конструкторе. Например, передать в конструктор не экземпляр формы, а ссылку на метод, который этот экземпляр может создать.

Постскриптум

Идея в том, что приложение начинается с формы ввода логина и пароля, эта форма появляется первой, а значит главная. После нажатия баттона Log In форма ввода логина и пароля исчезает и появляется основное окно.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *