Взаимодействие между формами windows forms c

Добавление форм в проект. Взаимодействие между формами в Windows Forms и Visual 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.
Если у нас одновременно открыта куча форм, то при закрытии главной закрывается все приложение и вместе с ним все остальные формы.

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();
        }
    }

Вот и все. Оказалось не все так сложно 😉

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

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

Перед открытием формы, передаем ссылку на нужный элемент в переменную 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
        
        [STAThread]
        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
        }
    }
}

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.

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.

.NET 4.x

Как передавать данные между формами

06.04.2012, 05:44. Показов 46738. Ответов 4


Hi!
Написал по сабжу статью (первоначально — себе в блог), но решил выложить тут. Полезнее будет, может кому и пригодится.

В процессе изучения C# вообще и WinForms в частности, у многих неофитов возникает вполне закономерный вопрос — а как передавать данные (в общем — объекты, но для начала хотя бы просто строки/числа). Кроме того, данные порой нужно передавать не только из основной формы в дочернюю, но и в обратном направлении. Для каждого из этих действий есть несколько способов реализации, и применение каждого из них зависит от контекста задачи, а также — от стиля и опыта программиста. Как правило, программисты выбирают себе несколько способов, которые используют в своих проектах. Я постарался в данной статье привести все известные мне способы, а так же их комбинации. Статья логически разделена на две части — прямая передача данных (из основной формы в дочернюю) и обратная.

Задача 1: Передать текстовую строку из основной формы в дочернюю
Реализация 1: Передать через конструктор дочерней формы
Самый простой способ. Класс дочерней формы конструируется таким образом, чтобы конструктор (или одна из его перегрузок) класса принимал в качестве аргумента или аргументов некие данные. Способ удобен тем, что в дочернюю форму можно передать практически неограниченное количество данных фактически любого типа. Неудобен он тем, что класс дочерней формы в этом случае становится слишком узкоспециализированным. При разработке небольших проектов это не почувствуется, но если вы возьметесь за масштабное модульное бизнес-приложение, сразу поймете всю узкость данного подхода. Но, тем не менее, не рассмотреть его было бы несправедливо.
Листинг 1.1.1. Основная форма:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    //Основная форма
    public partial class MasterForm : Form
    {
        public MasterForm()
        {
            InitializeComponent();
        }
 
        //Обрабатываем событие Click на кнопке
        private void SendB_Click(object sender, EventArgs e)
        {
            //Создаем экземпляр дочерней формы. В качестве аргумента конструктора указываем значение свойства Text текстбокса DataTB
            SlaveForm SF = new SlaveForm(DataTB.Text);
 
            //Показываем форму. В данном конкретном случае все равно как показывать: с помощью метода Show() либо ShowDialog()
            SF.Show();
        }
    }

Листинг 1.1.2. Дочерняя форма:

C#
1
2
3
4
5
6
7
8
9
10
    //Дочерняя форма
    public partial class SlaveForm : Form
    {
        public SlaveForm(String Data)
        {
            InitializeComponent();
            //Полученные в качестве аргумента данные напрямую пишем в свойство Text текстбокса
            InboxTB.Text = Data;
        }
    }

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

Реализация 2: Передать через public-переменную или свойство класса дочерней формы.
Способ чуть посложнее. Потребуется создать в классе дочерней формы дополнительную переменную или свойство (в данном случае — это не важно), и обработать событие Load дочерней формы.
Листинг 1.2.1. Основная форма:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    //Основная форма
    public partial class MasterForm : Form
    {
        public MasterForm()
        {
            InitializeComponent();
        }
 
        private void SendB_Click(object sender, EventArgs e)
        {
            //Создаем экземпляр формы
            SlaveForm SF = new SlaveForm();
 
            //Пишем в переменную InboxData данные.
            //ВНИМАНИЕ! Сначала нужно записать данные в переменную, а затем вызывать метод загрузки данных (Show()). 
            //В противном случае мы не получим данные в дочерней форме
            SF.InboxData = DataTB.Text;
 
            //Грузим дочернюю форму
            SF.Show();
        }
    }

Листинг 1.2.2. Дочерняя форма:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    //Дочерняя форма
    public partial class SlaveForm : Form
    {
        //Создаем переменную, доступную любому классу в пределах проекта
        public String InboxData = String.Empty;
        public SlaveForm()
        {
            InitializeComponent();
        }
 
        //Обрабатываем событие Load (загрузку формы), чтобы поместить полученный в переменную InboxData данные
        private void SlaveForm_Load(object sender, EventArgs e)
        {
            InboxTB.Text = InboxData;
        }
    }

Реализация 3: Передача данных через свойство/переменную статического класса.
Суть способа в следующем: использовать для временного буфера свойство или переменную статического класса. Данный способ несколько более универсальный. Хотя бы тем, что он не требует специализации класса дочерней формы, т.е. нам не придется добавлять в класс дочерней формы дополнительные свойства или переменные. Только обработать событие Load формы.

Листинг 1.3.1. Статический класс:

C#
1
2
3
4
5
6
//Статический класс, одна из переменных которого выступит в качестве буфера для данных
    public static class StaticData
    {
        //Буфер данных
        public static String DataBuffer = String.Empty;
    }

Листинг 1.3.2. Основная форма:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    //Основная форма
    public partial class MasterForm : Form
    {
        public MasterForm()
        {
            InitializeComponent();
        }
 
        private void SendB_Click(object sender, EventArgs e)
        {
            //При клике на кнопке обработчик события Click пишет строку из текстбокса в переменную статического класса,...
            StaticData.DataBuffer = DataTB.Text;
 
            //...создает экземпляр дочерней формы и отображает ее
            SlaveForm SF = new SlaveForm();
            SF.Show();
 
            //Опять же, для того, чтобы данные успешно отобразились в дочерней форме, запись их в переменную 
            //статического класса необходимо делать ДО вызова формы
        }
    }

Листинг 1.3.3. Дочерняя форма:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    //Дочерняя форма
    public partial class SlaveForm : Form
    {
        public SlaveForm()
        {
            InitializeComponent();
        }
 
        private void SlaveForm_Load(object sender, EventArgs e)
        {
            //При возникновении события Load обработчик считывает данные из статического буфера и отображает их в текстбоксе
            InboxTB.Text = StaticData.DataBuffer;
        }
    }

Реализация 4: Запись данных напрямую в TextBox дочерней формы через обработку события Load анонимным методом.
Не самый лучший вариант, попахивающий карри и индийскими слонами, но для полноты картины продемонстрирую и его. Суть способа в том, что в основной форме при обработке события Click на кнопке с помощью анонимного метода подписаться на событие Load дочерней формы и задать для этого события обработчик. А в обработчике уже производить присвоение свойству Text текстбокса дочерней формы каких-либо значений. Текстбоксу дочерней формы в этом случае должен быть присвоен модификатор public.
Листинг 1.4.1 Основная форма:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    //Основная форма
    public partial class MasterForm : Form
    {
        public MasterForm()
        {
            InitializeComponent();
        }
 
        //Обработчик события Click
        private void SendB_Click(object sender, EventArgs e)
        {
            //Создаем экземпляр формы
            SlaveForm SF = new SlaveForm();
 
            //С помощью анонимного метода обрабатываем событие Load дочерней формы в основной форме
            SF.Load += (sender1, e1) =>
                {
                    //В свойство Text текстбокса на дочерней форме пишем данные из свойста Text текстбокса основной формы
                    SF.InboxTB.Text = DataTB.Text;
                };
 
            //После того, как подписались на событие Load, загружаем форму
            SF.Show();
        }
    }

Листинг 1.4.2. Дочерняя форма:

C#
1
2
3
4
5
6
7
8
9
    //Класс дочерней формы. Тут мы ничего не делаем, за исключением того, что меняем модификатор доступа для 
    //текстбокса с private на public в свойствах этого текстбокса
    public partial class SlaveForm : Form
    {
        public SlaveForm()
        {
            InitializeComponent();
        }
    }

Задача 2. Передать данные из дочерней формы в основную
Реализация 1. Через статический класс. Тут, в общем то, все достаточно просто и похоже на подобную реализацию выше. Но есть и пара нюансов.
Поскольку по умолчанию основная форма «не знает», когда из дочерней в переменную статического класса будет записано значение, встает проблема — обновить текстбокс основной формы именно тогда, когда в статический класс будут внесены данные. В самом первом приближении это возможно при выполнении следующего условия — дочерняя форма открыта как диалог (т.е. управление передается на дочернюю форму при ее закрытии), а обновление текстбокса основной формы происходит после метода открытия дочерней формы.
Листинг 2.1.1. Статический класс

C#
1
2
3
4
5
6
//Статический класс
    public static class StaticData
    {
        //Статическая переменная, выступающая как буфер данных
        public static String DataBuffer = String.Empty;
    }

Листинг 2.1.2. Основная форма

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Основная форма
    public partial class MasterForm : Form
    {
        public MasterForm()
        {
            InitializeComponent();
        }
 
        //Вызов дочерней формы как диалога
        private void CallB_Click(object sender, EventArgs e)
        {
            SlaveForm SF = new SlaveForm();
            SF.ShowDialog();
            //Обновление текстбокса после закрытия дочерней формы
            DataTB.Text = StaticData.DataBuffer;
        }
    }

Листинг 2.1.3. Дочерняя форма

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Дочерняя форма
    public partial class SlaveForm : Form
    {
        public SlaveForm()
        {
            InitializeComponent();
        }
 
        private void SendB_Click(object sender, EventArgs e)
        {
            //По клику заполняем статическую переменную 
            StaticData.DataBuffer = OutboxTB.Text;
        }
    }

Реализация 2. Через событие закрытия окна.
При вызове дочерней формы мы можем с помощью анонимного метода подписаться на события вызываемой формы. Например, если мы подпишемся на событие закрытия окна, то сможем выполнить некие действия, когда дочерняя форма инициирует это событие (т.е. начнет закрываться).

Листинг 2.2.1. Основная форма

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    //Основная форма
    public partial class MasterForm : Form
    {
        public MasterForm()
        {
            InitializeComponent();
        }
 
        //Открываем дочернюю форму и подписываемся на ее события
        private void CallB_Click(object sender, EventArgs e)
        {
            //Создаем экземпляр формы
            SlaveForm SF = new SlaveForm();
 
            //Создаем анонимный метод - обработчик события FormClosing дочерней формы (возникающего перед закрытием)
            //Подписаться на событие необходимо до открытия дочерней формы
            //Использовать событие FormClosed не стоит, так как оно возникает уже после закрытия формы, когда все переменные формы уже уничтожены
            SF.FormClosing += (sender1, e1) =>
                {
                    //Обновляем текстбокс основной формы
                    DataTB.Text = SF.DataBuffer;
                };
 
            //Открывает форму на просмотр
            SF.Show();
        }
    }

Листинг 2.2.2. Дочерняя форма

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    //Дочерняя форма
    public partial class SlaveForm : Form
    {
        //Переменная, выполняющая роль буфера для данных
        //Переменная должна быть public, иначе мы не получим к ней доступ из основной формы
        public String DataBuffer = String.Empty;
        public SlaveForm()
        {
            InitializeComponent();
        }
 
        //Обрабатываем клик по кнопке
        private void SendB_Click(object sender, EventArgs e)
        {
            //Локальная переменная получает значение из текстбокса
            DataBuffer = OutboxTB.Text;
        }
    }

Кроме событий формы, можно подписаться на события любых public-компонентов. Но не рекомендую этого делать — это, конечно, легко и просто, но… некрасиво, что ли.

Реализация 3. Через события статического класса.
Опять задействуем посредника в виде статического класса. Однако применим на этот раз иной подход. В основной форме подпишемся на событие ValueChanged статического свойства DataBuffer. Но, поскольку свойство это «из коробки» не имеет подобных событий, его придется создать.

Листинг 2.3.1. Статический класс

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    //Статический класс
    public static class StaticData
    {
        //Описание делегата - обработчика события
        public delegate void ValueChangedEventHandler(object sender, EventArgs e);
 
        //Событие 
        public static event ValueChangedEventHandler ValueChanged;
 
        //Изолированная переменная - хранилище данных, передаваемых в свойство DataBuffer
        private static String dataBuffer = String.Empty;
 
        //Свойство DataBuffer
        public static String DataBuffer
        {
            get
            {
                return dataBuffer;
            }
            set
            {
                dataBuffer = value;
 
                //При изменении данных свойства вызывается событие ValueChanged
                ValueChanged(null, EventArgs.Empty);
            }
        }
    }

Листинг 2.3.2. Основная форма

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    //Основная форма
    public partial class MasterForm : Form
    {
        public MasterForm()
        {
            InitializeComponent();
        }
 
        //Обработка клика по кнопке
        private void CallB_Click(object sender, EventArgs e)
        {
            //Подписываемся на событие ValueChanged статического класса
            StaticData.ValueChanged += (sender1, e1) =>
                {
                    DataTB.Text = StaticData.DataBuffer;
                };
 
            //Создаем экземпляр формы
            SlaveForm SF = new SlaveForm();
 
            //Вызываем форму
            SF.Show();
        }
    }

Листинг 2.3.3. Дочерняя форма

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    //Дочерняя форма
    public partial class SlaveForm : Form
    {
        public SlaveForm()
        {
            InitializeComponent();
        }
 
        private void SendB_Click(object sender, EventArgs e)
        {
            //По клику на кнопке пишем данные из текстбокса в свойство статического класса
            StaticData.DataBuffer = OutboxTB.Text;
        }
    }

Если открывать дочернюю форму как диалог, данные в основной форме обновятся после закрытия дочерней. В противном случае данные обновятся сразу же. Подобный подход удобен, когда нужно организовать одновременный обмен данными между двумя формами. Причем, в отличие от большинства других вариантов, такой способ обмена доступен и для равнозначных форм (запущенных от одного, не участвующего в обмене родителя — например, MDI-окна). Достаточно просто заставить каждую форму слушать определенное событие статического класса-буфера.

На данный момент вроде как все. Скорее всего что-то забыл, поэтому к критике в комментариях буду прислушиваться особенно внимательно.
Best Regards, Aexx

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



5



Постановка задачи

Часто бывает, что к готовой программе, использующей одно окно, необходимо добавить некоторую новую функцию, например, ввод имени пользователя и пароля. Причем требуется использовать новое окно (диалоговую форму), которое будет открываться при инициализации события на главной форме. При этом данные об имени и пароле пользователя (передаваемые параметры) после закрытия вспомогательной диалоговой формы должны быть доступны для главной формы.

Предлагаю простейший способ такого взаимодействия через статическую переменную.

Напомним, что для  создания и отображения окна, используют экземпляры (переменные) класса Form, и методы Show() и ShowDialog().  Метод Show() отображает обычное окно, а ShowDialog — модальное.

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

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

Решение задачи

В пространстве имен проекта объявим структуру:

public struct LoginParol    // Что передавать
   {
       public string login;
       public string parol;
   }

В классе Form1 объявим статическую переменную:

static public LoginParol LogPar; // набор для обмена информацией

На Форму 1 поместим кнопку button1 («Ввод логина и пароля») и элемент groupBox1 с заголовком «Результат: Логин+Пароль  с Формы 2» и на нем элемент textBox1 для отображения результата ввода. Добавим в проект новую форму (Form2).

Вид главной формы (Форма 1):

311Рисунок 1.

Обработчик события  button1_Click зададим в виде:

private void button1_Click(object sender, EventArgs e)
   {
       Form2 newForm = new Form2();    // создаем объект класса Form2 
              // Примечание: Form2 должна быть добавлена в проект
       newForm.ShowDialog();           // Вызов формы-диалога
       textBox1.Text = LogPar.login + "/" + LogPar.parol; // Результат
   }

На Форму2 поместим две надписи (Label) и два элемента класса TextBox для задания имени и пароля, а также кнопку «Сохранить».

Вид Формы2 :

312Рисунок 2.

Обработчик события button1_Cick (имя кнопки на Form2 совпадает с именем кнопки на Form1, но это разные кнопки) зададим так:

  private void button1_Click(object sender, EventArgs e)
  {
     Form1.LogPar.login = textBox1.Text;
     Form1.LogPar.parol = textBox2.Text;
     this.Close();   // закрытие Формы2
  }

Программа готова. Полностью тексты файлов Form1.cs  и Form2.cs представлены ниже.

Form1.cs:

// Пример взаимодействия форм с передачей параметров
// (С) Вячеслав Рычков, 2018

using System;
using System.Windows.Forms;

namespace ВзаимодействиеФорм_ПередачаДанных
{
    public struct LoginParol    // Что передавать
    {
        public string login;
        public string parol;
    }
 
    public partial class Form1 : Form
    {
        static public LoginParol LogPar;      // набор для обмена информацией     

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Form2 newForm = new Form2();    // создаем объект класса Form2 
                  // Примечание: Form2 должна быть добавлена в проект
            newForm.ShowDialog();           // Вызов формы=диалога
            textBox1.Text = LogPar.login + "/" + LogPar.parol; // Результат
        }
    }
}

Form2.cs:

using System;
using System.Windows.Forms;
namespace ВзаимодействиеФорм_ПередачаДанных
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
            Form1.LogPar.login = textBox1.Text;
            Form1.LogPar.parol = textBox2.Text;
            this.Close();
        }
    }
}

При запуске программы открывается Форма 1 (рисунок 1). После нажатия кнопки «Ввод логина и пароля» открывается диалоговая Форма2 (пока она не закрыта, Форма 1 недоступна). На Форме 2 введем имя (Newton) и пароль (Isaak) пользователя и нажмем кнопку «Сохранить». Форма2 закроется, а в окне текстового редактора textBox1 мы увидим введенные логин и пароль:

313

Теперь на Форме1 вам доступны оба поля переменной LogPar: login и parol.

Поставленная задача решена. Используйте пример для своих приложений.


NEW: Наш Чат, в котором вы можете обсудить любые вопросы, идеи, поделиться опытом или связаться с администраторами.


Помощь проекту:

Передача параметров между формами в C#

Язык программирования C#

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

Способ №1
Передача параметров, используя связь между формами. (этот метод назвал я так сам — может есть и научное название).

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

В главной форме (родительской) запуск новой производим вот таким образом:

FormNew frm = new FormNew();
frm.Owner = this; //Передаём вновь созданной форме её владельца.
frm.Show(); 

После такого действия в новой форме мы можем обращаться к элементам родительской формы, вот так:

FormMain frm = (FormMain)this.Owner;
frm.MyFunc(); //MyFunc - это ваша функция основной формы.

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

Способ №2
По событиям (Делегаты)

1. Создаём в основном namespace (это в файле program.cs) класс:

public static class CallBackMy
    {
        public delegate void callbackEvent(string what);
        public static callbackEvent callbackEventHandler;
    }

2. Далее добавляем в форму приёмник (их может быть и несколько — что очень удобно):

public FormMy()
{
// Добавляем обработчик события - который запустит функцию Reload
CallBackMy.callbackEventHandler = new CallBackMy.callbackEvent(this.Reload);
InitializeComponent();
}

void Reload(string param)
{
//Здесь чего нибудь делаем.
//Это непосредственно то что выполнится по событию.
}

3. В форме источнике генерируем событие (там где это нам нужно).

CallBackMy.callbackEventHandler("Передаваемые данные.");

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


C шарп
программирование
Формы
Параметры

Понравилась статья? Поделить с друзьями:
  • Взаимодействие windows feature experience pack что это
  • Вечный поиск обновлений windows 7 x64
  • Вечный вход в систему windows 10
  • Вечный активатор для активации windows 7 64 bit 32
  • Вечный активатор windows 10 скачать торрент