.NET 4.x
Как передавать данные между формами
06.04.2012, 05:44. Показов 46733. Ответов 4
Hi!
Написал по сабжу статью (первоначально — себе в блог), но решил выложить тут. Полезнее будет, может кому и пригодится.
В процессе изучения C# вообще и WinForms в частности, у многих неофитов возникает вполне закономерный вопрос — а как передавать данные (в общем — объекты, но для начала хотя бы просто строки/числа). Кроме того, данные порой нужно передавать не только из основной формы в дочернюю, но и в обратном направлении. Для каждого из этих действий есть несколько способов реализации, и применение каждого из них зависит от контекста задачи, а также — от стиля и опыта программиста. Как правило, программисты выбирают себе несколько способов, которые используют в своих проектах. Я постарался в данной статье привести все известные мне способы, а так же их комбинации. Статья логически разделена на две части — прямая передача данных (из основной формы в дочернюю) и обратная.
Задача 1: Передать текстовую строку из основной формы в дочернюю
Реализация 1: Передать через конструктор дочерней формы
Самый простой способ. Класс дочерней формы конструируется таким образом, чтобы конструктор (или одна из его перегрузок) класса принимал в качестве аргумента или аргументов некие данные. Способ удобен тем, что в дочернюю форму можно передать практически неограниченное количество данных фактически любого типа. Неудобен он тем, что класс дочерней формы в этом случае становится слишком узкоспециализированным. При разработке небольших проектов это не почувствуется, но если вы возьметесь за масштабное модульное бизнес-приложение, сразу поймете всю узкость данного подхода. Но, тем не менее, не рассмотреть его было бы несправедливо.
Листинг 1.1.1. Основная форма:
C# | ||
|
Листинг 1.1.2. Дочерняя форма:
C# | ||
|
Думаю, все понятно и без дальнейших комментариев
Реализация 2: Передать через public-переменную или свойство класса дочерней формы.
Способ чуть посложнее. Потребуется создать в классе дочерней формы дополнительную переменную или свойство (в данном случае — это не важно), и обработать событие Load дочерней формы.
Листинг 1.2.1. Основная форма:
C# | ||
|
Листинг 1.2.2. Дочерняя форма:
C# | ||
|
Реализация 3: Передача данных через свойство/переменную статического класса.
Суть способа в следующем: использовать для временного буфера свойство или переменную статического класса. Данный способ несколько более универсальный. Хотя бы тем, что он не требует специализации класса дочерней формы, т.е. нам не придется добавлять в класс дочерней формы дополнительные свойства или переменные. Только обработать событие Load формы.
Листинг 1.3.1. Статический класс:
C# | ||
|
Листинг 1.3.2. Основная форма:
C# | ||
|
Листинг 1.3.3. Дочерняя форма:
C# | ||
|
Реализация 4: Запись данных напрямую в TextBox дочерней формы через обработку события Load анонимным методом.
Не самый лучший вариант, попахивающий карри и индийскими слонами, но для полноты картины продемонстрирую и его. Суть способа в том, что в основной форме при обработке события Click на кнопке с помощью анонимного метода подписаться на событие Load дочерней формы и задать для этого события обработчик. А в обработчике уже производить присвоение свойству Text текстбокса дочерней формы каких-либо значений. Текстбоксу дочерней формы в этом случае должен быть присвоен модификатор public.
Листинг 1.4.1 Основная форма:
C# | ||
|
Листинг 1.4.2. Дочерняя форма:
C# | ||
|
Задача 2. Передать данные из дочерней формы в основную
Реализация 1. Через статический класс. Тут, в общем то, все достаточно просто и похоже на подобную реализацию выше. Но есть и пара нюансов.
Поскольку по умолчанию основная форма «не знает», когда из дочерней в переменную статического класса будет записано значение, встает проблема — обновить текстбокс основной формы именно тогда, когда в статический класс будут внесены данные. В самом первом приближении это возможно при выполнении следующего условия — дочерняя форма открыта как диалог (т.е. управление передается на дочернюю форму при ее закрытии), а обновление текстбокса основной формы происходит после метода открытия дочерней формы.
Листинг 2.1.1. Статический класс
C# | ||
|
Листинг 2.1.2. Основная форма
C# | ||
|
Листинг 2.1.3. Дочерняя форма
C# | ||
|
Реализация 2. Через событие закрытия окна.
При вызове дочерней формы мы можем с помощью анонимного метода подписаться на события вызываемой формы. Например, если мы подпишемся на событие закрытия окна, то сможем выполнить некие действия, когда дочерняя форма инициирует это событие (т.е. начнет закрываться).
Листинг 2.2.1. Основная форма
C# | ||
|
Листинг 2.2.2. Дочерняя форма
C# | ||
|
Кроме событий формы, можно подписаться на события любых public-компонентов. Но не рекомендую этого делать — это, конечно, легко и просто, но… некрасиво, что ли.
Реализация 3. Через события статического класса.
Опять задействуем посредника в виде статического класса. Однако применим на этот раз иной подход. В основной форме подпишемся на событие ValueChanged статического свойства DataBuffer. Но, поскольку свойство это «из коробки» не имеет подобных событий, его придется создать.
Листинг 2.3.1. Статический класс
C# | ||
|
Листинг 2.3.2. Основная форма
C# | ||
|
Листинг 2.3.3. Дочерняя форма
C# | ||
|
Если открывать дочернюю форму как диалог, данные в основной форме обновятся после закрытия дочерней. В противном случае данные обновятся сразу же. Подобный подход удобен, когда нужно организовать одновременный обмен данными между двумя формами. Причем, в отличие от большинства других вариантов, такой способ обмена доступен и для равнозначных форм (запущенных от одного, не участвующего в обмене родителя — например, MDI-окна). Достаточно просто заставить каждую форму слушать определенное событие статического класса-буфера.
На данный момент вроде как все. Скорее всего что-то забыл, поэтому к критике в комментариях буду прислушиваться особенно внимательно.
Best Regards, Aexx
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
5
- Remove From My Forums
Какие способы передачи переменных между формами?
-
Общие обсуждения
-
Какие способы передачи переменных между формами в приложениях Windows Form на языке Visual C#?
-
Изменен тип
I.Vorontsov
22 марта 2010 г. 11:23 -
Перемещено
Tagore Bandlamudi
2 октября 2010 г. 21:58
MSDN Forums consolidation (От:Разработка Windows-приложений)
-
Изменен тип
Все ответы
-
Я обычно делаю свойство или публичный член класса формы. Но тогда надо передавать сам объект формы. Можно сделать сторонний Static Class для обмена данными.
Это корректно или обычно делают как-то иначе?
-
Один из способов передачи параметров между формами:
— в первой форме (Form1) объявить public переменную с модификатором static, например:
static public int i;
— задать значение ей, например при загрузке формы:
i = 5;
— во второй форме можно обратиться к переменной, например вывести значение переменной в заголовок формы:
this.Text = Form1.i.ToString();
-
На мой взгляд использовать сторонний Static Class целесообразно для «долгого» хранения переменных…
Если необходимо единовременно передать данные между формами, то делаю следующее:
1.В форму куда необходимо передать данные (ФормаКуда) в коде пишем:
public partial class ФормаКуда: Form
{
ФормаОтКуда mainForm = null;
public Otsrochka(ФормаОтКуда main){
InitializeComponent();
mainForm = main;
}2. Вызываем ФормаКуда из ФормаОтКуда:
ФормаКуда FormNew = new ФормаКуда (this);
FormNew .ShowDialog();
3. Манипулируем данными в ФормаКуда через mainForm. При этом необходимо чтобы переменные в ФормаОтКуда были Public
In the comments to the accepted answer, Neeraj Gulia writes:
This leads to tight coupling of the forms Form1 and Form2, I guess instead one should use custom events for such kind of scenarios.
The comment is exactly right. The accepted answer is not bad; for simple programs, and especially for people just learning programming and trying to get basic scenarios to work, it’s a very useful example of how a pair of forms can interact.
However, it’s true that the coupling that example causes can and should be avoided, and that in the particular example, an event would accomplish the same thing in a general-purpose, decoupled way.
Here’s an example, using the accepted answer’s code as the baseline:
Form1.cs:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.Button1Click += (s1, e1) => Lbl.Text = ((Form2)s1).Message;
frm.Show();
}
}
The above code creates a new instance of Form2
, and then before showing it, adds an event handler to that form’s Button1Click
event.
Note that the expression (s1, e1) => Lbl.Text = ((Form2)s1).Message
is converted automatically by the compiler to a method that looks something similar to (but definitely not exactly like) this:
private void frm_Message(object s1, EventArgs e1)
{
Lbl.Text = ((Form2)s1).Message;
}
There are actually lots of ways/syntaxes to implement and subscribe the event handler. For example, using an anonymous method as the above, you don’t really need to cast the sender
parameter; instead you can just use the frm
local variable directly: (s1, e1) => Lbl.Text = frm.Message
.
Going the other way, you don’t need to use an anonymous method. You could in fact just declare a regular method just like the compiler-generated one I show above, and then subscribe that method to the event: frm.Button1Click += frm_Message;
(where you have of course used the name frm_Message
for the method, just as in my example above).
Regardless of how you do it, of course you will need for Form2
to actually implement that Button1Click
event. That’s very simple…
Form2.cs:
public partial class Form2 : Form
{
public event EventHandler Button1Click;
public string Message { get { return txtMessage.Text; } }
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
In addition to the event, I’ve also declared a property Message
that exposes the Text
property (and only the Text
property, and only as read-only in fact) of the txtMessage
control. This allows the subscriber to the event to get the value and do whatever it needs to with it.
Note that all that the event does is to alert the subscriber that the button has in fact been clicked. It’s up to the subscriber to decide how to interpret or react to that event (e.g. by retrieving the value of the Message
property and assigning it to something).
Alternatively, you could in fact deliver the text along with the event itself, by declaring a new EventArgs
sub-class and using that for the event instead:
public class MessageEventArgs : EventArgs
{
public string Message { get; private set; }
public MessageEventArgs(string message)
{
Message = message;
}
}
public partial class Form2 : Form
{
public event EventHandler<MessageEventArgs> Button1Click;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, new MessageEventArgs(txtMessage.Text));
}
}
}
Then the subscriber can just retrieve the message value directly from the event object:
frm.Button1Click += (sender, e) => Lbl.Text = e.Message;
The important thing note in all of the above variations is that at no point does the class Form2
need to know anything about Form1
. Having Form1
know about Form2
is unavoidable; after all, that’s the object that will create a new Form2
instance and use it. But the relationship can be asymmetrical, with Form2
being usable by any object that needs the features it offers. By exposing the functionality as an event (and optionally with a property), it makes itself useful without limiting its usefulness to only the Form1
class.
Многие, кто начинал изучение WinForm приложений, сталкивались с проблемой обмена данными между окнами программы. Обмен данными между формами сводится к трем основным принципам: передача параметров в форму, получение данных из формы, изменение значений другой формы. Начнем по порядку.
1) Передача параметров в форму. Любой класс, должен иметь конструктор, и WinForm в этом случае не исключение. А следовательно очевидным является тот факт, что передача данных необходимых для инициализации формы необходимо проводить именно через конструктор формы. Приведем пример.
Создадим WinForm и перейдем к коду. Наблюдаем следующую картину:
public partial class Form1 : Form { public Form1() // <-- Конструктор формы по умолчанию { InitializeComponent(); } }
Допустим на данной форме размещен элемент textBox в который мы хотим установить значение, при открытии нашей формы. Тогда модифицируем наш код следующим образом:
public partial class Form1 : Form { public Form1() { InitializeComponent(); } public Form1(string text) // <-- Новый конструктор формы { InitializeComponent(); textBox.Text = text; } }
Важно: Все действия, выполняемые с объектами формы должны быть произведены после функции InitializeComponent()!
2-3) По сути задача получения данных из формы и изменение данных в форме сводистя к одной задаче. Пусть у нас есть две формы Form1 и Form2. В первой форме у нас есть три кнопки: open, read, write . Первая откроет вторую форму, в которой есть элемент textBox, Вторая покажет сообщение с текстом, введенным в textBox формы номер два, третья очистит textBox из Form2. Имеем:
public partial class Form1 : Form { private Form2 F2 = new Form2(); //<--Объявляем форму два как элемент класса формы один public Form1() { InitializeComponent(); } private void open_Click(object sender, EventArgs e) { F2.ShowDialog(); } private void read_Click(object sender, EventArgs e) { MessageBox.Show(F2.textBoxValue); } private void write_Click(object sender, EventArgs e) { F2.textBoxValue = String.Empty; } } public partial class Form2 : Form { public string textBoxValue //<--Данная конструкция позволяет получить доступ //к private элементам формы { get { return textBox.Text; } set { textBox.Text = value; } } public Form2() { InitializeComponent(); } }
Вот и все. Оказалось не все так сложно 😉
- Download demo project — 51.01 KB
Passing Data Between Forms
Introduction
Some of you would have faced a scenario where you wanted to pass data from one form to another in WinForms. Honestly, I too had a similar problem (that’s why I am writing this article!).
There are so many methods (How many? I don’t know) to pass data between forms in Windows application. In this article, let me take four important (easiest) ways of accomplishing this:
- Using constructor
- Using objects
- Using properties
- Using delegates
Let us see all the above methods in detail in the following sections.
For data to be passed between forms using any of the above methods, we need two forms and some controls. Let us start by following the steps given below.
Step 1
Create a new project and select Windows application. This will create a default form as “Form1
”. We can use this form for sending data.
Step 2
Add a textbox
and a button
to the form.
Step 3
Add another Windows Form for receiving the data and to display it. Right click the project and select Add->Add Windows Form. Enter a name or use the default name “Form2.cs” and click ok button.
Step 4
Add a label to the second form to display the text from form1
.
The Constructor Approach
This could be the easiest method of all. A method is invoked whenever you instantiate an object. This method is called a constructor. Code a constructor for form2
class with one string
parameter. In the constructor, assign the text to the label
’s text
property. Instantiate form2
class in form1
’s button click event handler using the constructor with one string
parameter and pass the textbox
’s text to the constructor.
Follow the steps given below:
Step 1
Code a constructor for form2
class as below:
public Form2(string strTextBox) { InitializeComponent(); label1.Text=strTextBox; }
Step 2
Instantiate form2
class in form1
’s button click event handler as below:
private void button1_Click(object sender, System.EventArgs e) { Form2 frm=new Form2(textBox1.Text); frm.Show(); }
The Object Approach
Objects are reference types, and are created on the heap, using the keyword new
. Here we are going to pass data using objects. The approach is simple; in form2
we are going to instantiate form1
class.
Then instantiate form2
in the button click event handler of form1
. After this we are going to pass form1
object to the form2
using form2
’s form1
object. The last step is to invoke the form2
window by calling the form2
’s show
method.
Follow the below steps:
Step 1
Change the access modifier for textbox
in form1
to public
:
public class Form1 : System.Windows.Forms.Form { public System.Windows.Forms.TextBox textBox1;
Step 2
In the button click event-handler, add the following code:
private void btnSend_Click(object sender, System.EventArgs e) { Form2 frm= new Form2(); frm.frm1=this; frm.Show(); }
Step 3
In form2.cs, instantiate form1
class:
public class Form2 : System.Windows.Forms.Form { private System.Windows.Forms.Label label1; public Form1 frm1;
Step 4
In Form2
’s Load
method, type cast the object (frm1
) of form1
to Form1
and access form1
’s textbox
and assign its text to label
’s text.
private void Form2_Load(object sender, System.EventArgs e) { label1.Text=((Form1)frm1).textBox1.Text; }
The Properties Approach
Properties allow clients to access class state as if they were accessing member fields directly, while actually implementing that access through a class method. In this method, we are going to add one property to each form. In form1
we are going to use one property for retrieving value from the textbox
and in form2
, one property to set the label
’s text property. Then, in form1
’s button click event handler, we are going to instantiate form2
and use the form2
’s property to set the label
’s text.
Follow the below steps:
Step 1
Add a property in form1
to retrieve value from textbox
:
public string _textBox1 { get{return textBox1.Text;} }
Step 2
Add a property in form2
to set the label
s’ text
:
public string _textBox { set{label1.Text=value;} }
Step 3
In form1
’s button click event handler, add the following code:
private void button1_Click(object sender, System.EventArgs e) { Form2 frm=new Form2(); frm._textBox=_textBox1; frm.Show(); }
The Delegates Approach
Technically, a delegate
is a reference type used to encapsulate a method with a specific signature and return type. You can encapsulate any matching method in that delegate
. Here we are going to create a delegate
with some signature and assign a function to the delegate
to assign the text
from textbox
to label
.
Follow the below steps:
Step 1
Add a delegate
signature to form1
as below:
public delegate void delPassData(TextBox text);
Step 2
In form1
’s button click event handler, instantiate form2
class and delegate
. Assign a function in form2
to the delegate
and call the delegate
as below:
private void btnSend_Click(object sender, System.EventArgs e) { Form2 frm= new Form2(); delPassData del=new delPassData(frm.funData); del(this.textBox1); frm.Show(); }
Step 3
In form2
, add a function to which the delegate
should point to. This function will assign textbox
’s text
to the label
:
public void funData(TextBox txtForm1) { label1.Text = txtForm1.Text; }
Conclusion
These four approaches are very simple in implementing data passing between forms. There are also other methods available in accomplishing the same. Source code for the methods I stated above is given at the top for download. It is time for you to put on your thinking cap and find other ways of doing this. Happy coding!!!
History
- 16th May, 2006: Initial post
Thiagu is living in Bangalore, India. He has started coding when he was 12 years old. His native is Madurai, a historic city in south India. He loves to code in C#. He frequents code project when he is not coding. Thiagu loves reading Dan Brown and Michael Crichton novels. He is very much interested in Artificial Intelligence (AI). To view his blog — http://csharpnet.blogspot.com
- Download demo project — 51.01 KB
Passing Data Between Forms
Introduction
Some of you would have faced a scenario where you wanted to pass data from one form to another in WinForms. Honestly, I too had a similar problem (that’s why I am writing this article!).
There are so many methods (How many? I don’t know) to pass data between forms in Windows application. In this article, let me take four important (easiest) ways of accomplishing this:
- Using constructor
- Using objects
- Using properties
- Using delegates
Let us see all the above methods in detail in the following sections.
For data to be passed between forms using any of the above methods, we need two forms and some controls. Let us start by following the steps given below.
Step 1
Create a new project and select Windows application. This will create a default form as “Form1
”. We can use this form for sending data.
Step 2
Add a textbox
and a button
to the form.
Step 3
Add another Windows Form for receiving the data and to display it. Right click the project and select Add->Add Windows Form. Enter a name or use the default name “Form2.cs” and click ok button.
Step 4
Add a label to the second form to display the text from form1
.
The Constructor Approach
This could be the easiest method of all. A method is invoked whenever you instantiate an object. This method is called a constructor. Code a constructor for form2
class with one string
parameter. In the constructor, assign the text to the label
’s text
property. Instantiate form2
class in form1
’s button click event handler using the constructor with one string
parameter and pass the textbox
’s text to the constructor.
Follow the steps given below:
Step 1
Code a constructor for form2
class as below:
public Form2(string strTextBox) { InitializeComponent(); label1.Text=strTextBox; }
Step 2
Instantiate form2
class in form1
’s button click event handler as below:
private void button1_Click(object sender, System.EventArgs e) { Form2 frm=new Form2(textBox1.Text); frm.Show(); }
The Object Approach
Objects are reference types, and are created on the heap, using the keyword new
. Here we are going to pass data using objects. The approach is simple; in form2
we are going to instantiate form1
class.
Then instantiate form2
in the button click event handler of form1
. After this we are going to pass form1
object to the form2
using form2
’s form1
object. The last step is to invoke the form2
window by calling the form2
’s show
method.
Follow the below steps:
Step 1
Change the access modifier for textbox
in form1
to public
:
public class Form1 : System.Windows.Forms.Form { public System.Windows.Forms.TextBox textBox1;
Step 2
In the button click event-handler, add the following code:
private void btnSend_Click(object sender, System.EventArgs e) { Form2 frm= new Form2(); frm.frm1=this; frm.Show(); }
Step 3
In form2.cs, instantiate form1
class:
public class Form2 : System.Windows.Forms.Form { private System.Windows.Forms.Label label1; public Form1 frm1;
Step 4
In Form2
’s Load
method, type cast the object (frm1
) of form1
to Form1
and access form1
’s textbox
and assign its text to label
’s text.
private void Form2_Load(object sender, System.EventArgs e) { label1.Text=((Form1)frm1).textBox1.Text; }
The Properties Approach
Properties allow clients to access class state as if they were accessing member fields directly, while actually implementing that access through a class method. In this method, we are going to add one property to each form. In form1
we are going to use one property for retrieving value from the textbox
and in form2
, one property to set the label
’s text property. Then, in form1
’s button click event handler, we are going to instantiate form2
and use the form2
’s property to set the label
’s text.
Follow the below steps:
Step 1
Add a property in form1
to retrieve value from textbox
:
public string _textBox1 { get{return textBox1.Text;} }
Step 2
Add a property in form2
to set the label
s’ text
:
public string _textBox { set{label1.Text=value;} }
Step 3
In form1
’s button click event handler, add the following code:
private void button1_Click(object sender, System.EventArgs e) { Form2 frm=new Form2(); frm._textBox=_textBox1; frm.Show(); }
The Delegates Approach
Technically, a delegate
is a reference type used to encapsulate a method with a specific signature and return type. You can encapsulate any matching method in that delegate
. Here we are going to create a delegate
with some signature and assign a function to the delegate
to assign the text
from textbox
to label
.
Follow the below steps:
Step 1
Add a delegate
signature to form1
as below:
public delegate void delPassData(TextBox text);
Step 2
In form1
’s button click event handler, instantiate form2
class and delegate
. Assign a function in form2
to the delegate
and call the delegate
as below:
private void btnSend_Click(object sender, System.EventArgs e) { Form2 frm= new Form2(); delPassData del=new delPassData(frm.funData); del(this.textBox1); frm.Show(); }
Step 3
In form2
, add a function to which the delegate
should point to. This function will assign textbox
’s text
to the label
:
public void funData(TextBox txtForm1) { label1.Text = txtForm1.Text; }
Conclusion
These four approaches are very simple in implementing data passing between forms. There are also other methods available in accomplishing the same. Source code for the methods I stated above is given at the top for download. It is time for you to put on your thinking cap and find other ways of doing this. Happy coding!!!
History
- 16th May, 2006: Initial post
Thiagu is living in Bangalore, India. He has started coding when he was 12 years old. His native is Madurai, a historic city in south India. He loves to code in C#. He frequents code project when he is not coding. Thiagu loves reading Dan Brown and Michael Crichton novels. He is very much interested in Artificial Intelligence (AI). To view his blog — http://csharpnet.blogspot.com