Открытие второй формы и передача данных в главную форму. Добавление форм. Взаимодействие между формами C открыть форму из другой формы

Последнее обновление: 31.10.2015

Чтобы добавить еще одну форму в проект, нажмем на имя проекта в окне Solution Explorer (Обозреватель решений) правой кнопкой мыши и выберем Add(Добавить)->Windows Form...

Дадим новой форме какое-нибудь имя, например, Form2.cs :

Итак, у нас в проект была добавлена вторая форма. Теперь попробуем осуществить взаимодействие между двумя формами. Допустим, первая форма по нажатию на кнопку будет вызывать вторую форму. Во-первых, добавим на первую форму Form1 кнопку и двойным щелчком по кнопке перейдем в файл кода. Итак, мы попадем в обработчик события нажатия кнопки, который создается по умолчанию после двойного щелчка по кнопке:

Private void button1_Click(object sender, EventArgs e) { }

Теперь добавим в него код вызова второй формы. У нас вторая форма называется Form2, поэтому сначала мы создаем объект данного класса, а потом для его отображения на экране вызываем метод Show:

Private void button1_Click(object sender, EventArgs e) { Form2 newForm = new Form2(); newForm.Show(); }

Теперь сделаем наоборот - чтобы вторая форма воздействовала на первую. Пока вторая форма не знает о существовании первой. Чтобы это исправить, надо второй форме как-то передать сведения о первой форме. Для этого воспользуемся передачей ссылки на форму в конструкторе.

Итак перейдем ко второй форме и перейдем к ее коду - нажмем правой кнопкой мыши на форму и выберем View Code (Просмотр кода). Пока он пустой и содержит только конструктор. Поскольку C# поддерживает перегрузку методов, то мы можем создать несколько методов и конструкторов с разными параметрами и в зависимости от ситуации вызывать один из них. Итак, изменим файл кода второй формы на следующий:

Using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace HelloApp { public partial class Form2: Form { public Form2() { InitializeComponent(); } public Form2(Form1 f) { InitializeComponent(); f.BackColor = Color.Yellow; } } }

Фактически мы только добавили здесь новый конструктор public Form2(Form1 f) , в котором мы получаем первую форму и устанавливаем ее фон в желтый цвет. Теперь перейдем к коду первой формы, где мы вызывали вторую форму и изменим его на следующий:

Private void button1_Click(object sender, EventArgs e) { Form2 newForm = new Form2(this); newForm.Show(); }

Поскольку в данном случае ключевое слово this представляет ссылку на текущий объект - объект Form1, то при создании второй формы она будет получать ее (ссылку) и через нее управлять первой формой.

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

Мы можем также создавать объекты и текущей формы:

Private void button1_Click(object sender, EventArgs e) { Form1 newForm1 = new Form1(); newForm1.Show(); Form2 newForm2 = new Form2(newForm1); newForm2.Show(); }

При работе с несколькими формами надо учитывать, что одна из них является главной - которая запускается первой в файле Program.cs. Если у нас одновременно открыта куча форм, то при закрытии главной закрывается все приложение и вместе с ним все остальные формы.

Несмотря на то, что моё мнение о микрософтовском Visual Studio по-прежнему , иногда приходится что-то делать и на нём. Если смириться с тем, что пишем мы при этом, собственно, не на C++, а на так называемом C++/CLI , работа с привычными визуальными компонентами будет не так уж сильно отличаться от тех же Борландовских сред. А вот способно, по сравнению с Builder"ом, создать проблемы. Рассмотрим 3 типовых ситуации работы с приложением, содержащим больше одной формы. Среда примера - бесплатная Visual C++ 2010 Express , предполагается, что главная форма имеет имя по умолчанию Form1 .

Пример конструирования и программного вызова формы

Этот код можно выполнить, например, по нажатию кнопки в главной форме Form1.

Form ^ form2 = gcnew Form(); Button^ button2 = gcnew Button(); button2->Text = L"OK"; button2->Location = Point(10,10); form2->Text = L"Моё окно"; form2->HelpButton = true; form2->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog; form2->StartPosition = FormStartPosition::CenterScreen; form2->Controls->Add(button2); form2->ShowDialog();

Для добавления обработчика нажатия программно сгенерированной кнопки button2 достаточно перед последней строкой кода написать:

Button2->Click += gcnew System::EventHandler(this, &Form1::button2_Click);

До того, как будет вызван метод form2->ShowDialog() или form2->Show();

При этом код обработчика размещён в текущем модуле Form1.h:

Private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { MessageBox::Show("Here"); }

Вызвать другую форму из главной формы

В меню выберем Проект - Добавить новый элемент - Форма - имя Form2

Добавим оператор

#include "Form2.h"

перед первым namespace в Form1.h (то есть, в самое начало файла).

Включим указатель на экземпляр класса в секцию public класса Form1:

Form2 ^ F2;

Добавим код там, где нужно создать и вызвать вторую форму:

F2=gcnew Form2(); F2->Show();

Для программного удаления второй формы подойдёт код

Delete F2;

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

Опишем нужные данные в классе формы Form1 (здесь имя и namespace проекта Tabulator , если нужно, замените на своё):

Static const int MAX_FORMS = 100; //Максимальное количество форм int FormCount; //Счётчик форм array ^F2; //Указатель на массив форм

Потом инициализируем данные по событию Load главной формы:

FormCount=0; F2 = gcnew array(MAX_FORMS);

Затем реализуем код для создания очередной формы

If (FormCountShow(); } else MessageBox::Show("Слишком много форм!");

и её удаления:

If (FormCount) { delete F2; FormCount--; }

Если мы хотим создавать дочерние формы не отдельно, а внутри родительской формы, то в свойствах Form1 нужно указать, что она "предок" (установить свойство IsMdiParent = true), а перед показом дочерней формы оператором F2->Show() пометить её как потомка Form1:

F2->MdiParent = this;

Вызвать из дочерней формы метод родительской формы

Нам едва ли обойтись без привлечения файлов.cpp, что неплохо - писать код в файлах.h правильного Си"шника вообще ломает:)

Распишем процесс по шагам.

1) Имеются 2 формы - Form1 и Form2 , на Form1 располагаются Button (button1 , будет открывать вторую форму) и Label (label1 , здесь будем менять текст). На Form2 - button1 , по нажатию на которую будет происходить смена текста в label1 .

2) Так как нам из первой формы нужно иметь доступ ко второй, а из второй к первой, то будет возникать проблема перекрестных ссылок (когда Form1.h ссылается на Form2.h , который, в свою очередь, опять ссылается на Form1.h). Для того, чтобы этого избежать, код первой формы (Form1), который будет иметь доступ ко второй форме (Form2), мы вынесем из.h-файла в.cpp файл. Таким образом нужно создать файл Form1.cpp .

3) Объявить открытый метод Set в Form1.h для того, чтобы можно было изменить текст label1 (код можно написать в конце файла, после #pragma endregion):

Public: void Set(String^ text) { label1->Text = text; }

4) В файле Form2.h подключаем Form1.h (в начале):

#include "Form1.h"

и создаем конструктор, который будет принимать и сохранять ссылку на первую форму для дальнейшего использования:

Form2(Form1^ parent) { InitializeComponent(); parentForm = parent; } //ниже сразу ниже можно прописать ссылку: private: Form1^ parentForm;

5) По клику кнопки в Form2 будем вызывать метод Set родительской формы:

Private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { parentForm->Set("hello from form2"); parentForm->Show(); this->Hide(); }

6) Осталось в первой форме сделать открытие второй формы. Для этого из Form1.h обработчик нажатия кнопки переносим в Form1.cpp , а в.h-файле оставляем только его объявление.

Вопрос, рассматриваемый в данной статье, скорее относится к теме построения архитектуры приложения, а не конкретно рассматриваемой проблемы. Передавать данные от одной формы в другую вовсе не составляет труда. Для этого достаточно контрол, данные которого мы хотим получить, сделать открытым, то есть пометить модификатором public . Также, возможен и другой вариант. Например, в первой форме мы создаем объект второй формы, передав в конструктор ссылку на себя, то есть, передав из первой формы во вторую ссылку на первую
SecondForm secondForm = new SecondForm (this );
Естественно, перед этим следует позаботиться о создании перегрузки конструктора второй формы.

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

Решение данной проблемы достаточно простое. Обратимся непосредственно к коду. В дизайнере создаем главную форму (она будет запускаться при запуске приложения). Поместим один TextBox , Lable и Button .

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

Аналогично первой, она имеет те же контролы. Больше нам и не надо. Точка входа в приложение запускает главную форму:

Using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace From1FormTo2 { static class Program { // The main entry point for the application. static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } } }

Код главной формы выглядит так:

Using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace From1FormTo2 { public partial class MainForm: Form { //вторая форма SecondForm secondForm; //конструктор public MainForm() { InitializeComponent(); } //обработчик события передачи данных //от главной формы ко второй private void btn_mainForm_Click(object sender, EventArgs e) { secondForm = new SecondForm(tb_mainForm.Text.Trim()); secondForm.ShowDialog(); if (secondForm.DialogResult == DialogResult.OK) tb_mainForm.Text = secondForm.ReturnData(); } } }

Соответственно, не забудьте подключить кнопку на событие Click . Здесь, в классе главной формы, есть поле SecondForm secondForm , представляющее объект- вторую форму. При нажатии на кнопке «Передать», создается вторая форма (вызывается перегруженный конструктор, его мы еще создадим) и запускается методом ShowDialog() . В данном случае нам подходит именно этот метод. При чем, после этого мы обязательно проверяем, не закрыли ли вторую форму, а выполнили клик по её кнопке. Если, на второй форме был выполнен клик по кнопке, значит первая форма должна принять данные от второй. Это происходит путем вызова метода ReturnData() у второй формы.

Теперь самое интересное – код второй формы:

Using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace From1FormTo2 { public partial class SecondForm: Form { //перегруженный конструктор public SecondForm(string data) { InitializeComponent(); tb_secondForm.Text = data; } //обработчик события передачи данных //от второй формы к главной private void btn_secondForm_Click (object sender, EventArgs e) { this.DialogResult = DialogResult.OK; } //открытый метод для доступа к //текстовому полю данной формы public string ReturnData() { return (tb_secondForm.Text.Trim()); } } }

Как видим, имеется единственная перегрузка конструктора, который принимает тип string . Помним, что мы пытаемся передавать текст из TextBox. В конструкторе происходит плановая инициализация компонент и установка текста текстового поля в переданное значение от первой формы. Далее, подписавшись на событие Click для кнопки второй формы, мы создали обработчик btn_secondForm_Click , который и имитирует работу кнопки «Ok» любого диалогового окна. Таким образом, нажимая на кнопке «Отправить» (второй формы), мы приводим в исполнение условие

(secondForm .DialogResult == DialogResult .OK)

Первой формы, ввиду чего, вызывая метод secondForm .ReturnData() , мы устанавливаем тектовое поле первой формы в значение тектового поля второй формы.

Работа данного метода, я думаю, уже не требует пояснений. Он просто возвращает текст из единственного текстового поля, при этом, оставляя его приватным.

В итоге, мы передали данные во вторую форму из первой и со второй в первую не нарушая принципы инкапсуляции.

Попробуйте внести текст «ааа» в текстовое поле первой формы и выполнить нажатие на кнопке. Вы увидите в открывшейся второй форме этот текст в её текстовом поле. Попробуйте изменить текст на «ааа ппп» и нажать на кнопку. Вы увидите как после закрытия второй формы данный текст отобразится в текстовом поле главной формы.

Теперь, я думаю, вы будете более правильно осуществлять передачи данных между формами. В следующей статье мы поговорим, как в приложениях ASP.NET.

By admin.

Изучение C#медленно. но верно продолжается. Буквально недавно я
приводил пример того, как в Visual C# открыть из одной формы другую. В принципе всё просто.

Сегодня появилась следующая задача: из главной формы приложения запустить модальную форму, эта форма при закрытии должна передать в контролы на главной форме какие-либо данные (текст, значения свойств и т.д.). Решить эту задачу способом, описанном в прошлом посте про формы не представляется возможным, т.к. в этом случае мы просто создаем новый объект формы с новыми значениями всех свойств. Благо в C# есть замечательный сборщик мусора…Но суть не в сборщике, а в том как в C# открыть дочернюю форму, а потом из неё обратно добраться до главной?

Для начала зададимся начальными (исходными) данными.

Итак. У нас есть главная форма приложения:

На этой форме также находится TextBox с именем TBDialog и кнопка Button по клику на которой мы должны:

  1. Передать значение свойства Text из TBDialog в TBMain;
  2. Закрыть fDialog;

Теперь рассмотрим весь процесс работы по порядку.

Во-первых, стоит всегда помнить, что по умолчанию для всех свойств, переменных и методов в C# назначается модификатор private – следовательно, чтобы из второй формы добраться до контрола на первой нам необходимо выставить у TBMain модификатор public самостоятельно. Для этого выбираем элемент TBMain в конструкторе формы, переходим в окно свойств и меняем значение свойства Modifiers с private на public.

Теперь TBMain будет виден в других объектах. Движемся далее. Для того, чтобы открыть форму в модальном режиме нам необходимо воспользоваться одним из двух вариантов метода ShowDialog():

public DialogResult ShowDialog() ; public DialogResult ShowDialog(IWin32Window owner) ;

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

Для примера, воспользуемся вторым вариантом метода ShowDialog() и покажем вторую форму модально. Для этого напишем следующее:

Здесь я воспользовался снова ключевым словом this , которое указывает на текущий объект, т.е. задал в качестве владельца главную форму (fMain ). Теперь переходим непосредственно к решению нашей задаче и ответим на вопрос: как передать значение из одной формы в другую? У каждого контрола имеется замечательное свойство Owner – которое указывает на родителя:

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

Иногда бывает нужно обратиться к элементам какой-то формы из другой в процессе выполнения программы. Например, есть форма Form1, из нее мы открываем другую Form2 и теперь, работая в форме Form2 нужно обратиться, получить доступ к элементам родительской формы Form1. Я нашел несколько способов как это сделать.

1-й способ. Передача ссылки в public переменную.

Namespace WindowsApplication1 { public partial class Form1: Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Form2 frm = new Form2(); frm.but1 = this.button1; // передаем ссылку на кнопку в форму Form2 frm.ShowDialog(); } } }

В форме Form2 переменная, в которую передавали ссылку, будет теперь соответствовать кнопке button1 из формы Form1

Namespace WindowsApplication1 { public partial class Form2: Form { public Button but1; // эта переменная будет содержать ссылку на кнопку button1 из формы Form1 public Form2() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { but1.Text = "test"; // меняем текст на кнопке button1 формы Form1 } } }

2-й способ. Передача ссылки в дочернюю форму.

Суть примерна та же, то и в 1-м способе. При открытии формы Form2 передаем в нее ссылку на элемент, который планируем потом менять.

Namespace WindowsApplication1 { public partial class Form1: Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Form2 frm = new Form2(this.button1); // передаем ссылку на кнопку в форму Form2 frm.ShowDialog(); } } }

Теперь в форме Form2 нужно создать переменную, которая будет содержать ссылку на эту кнопку и через нее будем обращаться к кнопке на Form1 (строки 5,7,9 и 15).

Namespace WindowsApplication1 { public partial class Form2: Form { private Button but1; // эта переменная будет содержать ссылку на кнопку button1 из формы Form1 public Form2(Button but) // получаем ссылку на кнопку в переменную but { but1 = but; // теперь but1 будет ссылкой на кнопку button1 InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { but1.Text = "test"; // меняем текст на кнопке button1 формы Form1 } } }

3-й способ. Доступ ко всей родительской форме.

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

Шаг 1. В файле Program.cs создаем публичную переменную f1 (строка 5).

Namespace WindowsApplication1 { static class Program { public static Form1 f1; // переменная, которая будет содержать ссылку на форму Form1 static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } }

Шаг 2. Открываем Form1.Designer.cs и в нем у элементов, к которым нужно будет обратиться из другой формы, меняем private на public . Например, сделаем доступной для изменений кнопку button1 на форме Form1.

Public System.Windows.Forms.Button button1; // заменили private на public

Шаг 3 . При создании формы Form1 присваиваем переменной f1 ссылку на эту форму (строка 7)

Namespace WindowsApplication1 { public partial class Form1: Form { public Form1() { Program.f1 = this; // теперь f1 будет ссылкой на форму Form1 InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Form2 frm = new Form2(); frm.ShowDialog(); } } }

Шаг 4. Теперь из абсолютно любой формы или из любого класса можно обратиться к элементу button1 находящемуся на Form1 так: Program.f1.button1. Например, пусть кнопка в Form2 поменяет текст кнопки на Form1:

Namespace WindowsApplication1 { public partial class Form2: Form { public Form2() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Program.f1.button1.Text = "test"; // Меняем текст на кнопке формы Form1 } } }