1. Как создать вторую форму
Любая форма представляет из себя класс, унаследованный от Form.
Экземпляр главной формы создается в файле Program.cs по умолчанию.
namespace NS
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); // <- вот тут
}
}
}
Чтобы отобразить вторую форму, надо создать экземпляр этого класса (Form2), например в обработчике события главной
private void button1_Click(object sender, EventArgs e)
{
Form2 f = new Form2(); // создаем
f.ShowDialog(); // показываем
f.Show() // или так
}
При этом ShowDialog() блокирует главную форму, т.е. управление вернется в нее, только по закрытию второй формы, а Show() просто отображает вторую форму, т.е. будут доступны обе формы.
2. Как передать данный из одной формы в другую
Часто возникает необходимость передать данные из одной формы в другую, я придумал 7 способов, у каждого свои недостатки и достоинства.
2.1 Изменение модификатора доступа
В Form2 Установить модификатор доступа для контрола/поля public
В любом месте Form1
Form2 f = new Form2(); f.ShowDialog(); this.textBox1.Text = f.textBox1.Text;
+ Самый быстрый в реализации и удобный способ
– Противоречит всем основам ООП
– Возможна передача только из более поздней формы в более раннюю
– Форма f показывается только с использованием ShowDialog(), т.е. в первую форму управление вернется только по закрытию второй. Избежать этого можно, сохранив ссылку на вторую форму в поле первой формы
2.2 Использование открытого свойства/метода. Способ очень похож на первый
В классе Form2 определяем свойство (или метод)
public string Data
{
get
{
return textBox1.Text;
}
}
В любом месте Form1
Form2 f = new Form2(); f.ShowDialog(); this.textBox1.Text = f.Data;
+ Противоречит не всем основам ООП
– Минусы те же
2.3 Передача данных в конструктор Form2
Изменяем конструктор Form2
public Form2(string data)
{
InitializeComponent();
//Обрабатываем данные
//Или записываем их в поле
this.data = data;
}
string data;
А создаем форму в любом месте Form1 так:
Form2 f = new Form2(this.textBox1.Text); f.ShowDialog(); //Или f.Show();
+ Простой в реализации способ
+ Не нарушает ООП
– Возможна передача только из более ранней формы в более позднюю
2.4 Передача ссылки в конструктор
Изменяем конструктор Form2
public Form2(Form1 f1)
{
InitializeComponent();
//Обрабатываем данные
//Или записываем их в поле
string s = f1.textBox1.Text;
}
А создаем форму в любом месте Form1 так, т.е. передаем ей ссылку на первую форму
Form2 f = new Form2(this); f.ShowDialog(); //Или f.Show();
+ Доступ ко всем открытым полям/функциям первой формы
+ Передача данных возможна в обе стороны
– Нарушает ООП
2.5 Используем свойство ‘родитель’
При создании второй формы устанавливаем владельца
Form2 f = new Form2(); f.Owner = this; f.ShowDialog();
Во второй форме определяем владельца
Form1 main = this.Owner as Form1;
if(main != null)
{
string s = main.textBox1.Text;
main.textBox1.Text = "OK";
}
+ Доступ ко всем открытым полям/функциям первой формы
+ Передача данных возможна в обе стороны
+ Не нарушает ООП
2.6 Используем отдельный класс
Создаем отдельный класс, лучше статический, в основном namespace, т.е. например в файле Program.cs
static class Data
{
public static string Value { get; set; }
}
Его открытые свойства/методы доступны из любой формы.
Data.Value = "111";
+ Самый удобный способ, когда данные активно используются несколькими формами.
2.7 Использование функций обратного вызова
2.7.1 Передача метода в конструктор
Создаем в основном namespace делегат
public delegate void MyDelegate(string data);
В Form1 создаем метод, который будет обрабатывать принятые данные
void func(string param)
{
// обработка
}
Создаем вторую форму так:
Form2 f = new Form2(new MyDelegate(GetData)); f.ShowDialog();
При этом изменяем конструктор второй формы, чтобы он принимал делегат
MyDelegate d;
public Form2(MyDelegate sender)
{
InitializeComponent();
d= sender;
}
И в любой момент отправляем данные
d(textBox1.Text);
//Program.cs
using System;
using System.Windows.Forms;
namespace NS
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
public delegate void MyDelegate(string data);
}
//Form1.cs
using System;
using System.Windows.Forms;
namespace NS
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f = new Form2(new MyDelegate(func));
f.ShowDialog();
}
void func(string param)
{
MessageBox.Show(param + "!");
}
}
}
//Form2.cs
using System;
using System.Windows.Forms;
namespace NS
{
public partial class Form2 : Form
{
private MyDelegate d;
public Form2(MyDelegate sender)
{
InitializeComponent();
d = sender;
}
private void button1_Click(object sender, EventArgs e)
{
d(textBox1.Text);
}
}
}
2.7.2 Создание отдельного класса с делегатом
Создаем в основном namespace отдельный класс
public static class Data
{
public delegate void MyEvent(string data);
public static MyEvent EventHandler;
}
В первой форме добавляем обработчик
void func(string param)
{
MessageBox.Show(param);
}
и инициализируем EventHandler
Data.EventHandler = new Data.MyEvent(func);
Вторую форму создаем обычным способом и вызываем из нее
Data.EventHandler(textBox1.Text);
//Program.cs
using System;
using System.Windows.Forms;
namespace NS
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
public static class Data
{
public delegate void MyEvent(string data);
public static MyEvent EventHandler;
}
}
//Form1.cs
using System;
using System.Windows.Forms;
namespace NS
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Data.EventHandler = new Data.MyEvent(func);
}
private void button1_Click(object sender, EventArgs e)
{
Form2 f = new Form2();
f.ShowDialog();
}
void func(string param)
{
MessageBox.Show(param + "!");
}
}
}
//Form2.cs
using System;
using System.Windows.Forms;
namespace NS
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Data.EventHandler(textBox1.Text);
}
}
}
+ Наиболее гибкий способ передачи данных
– Сложен в реализации и понимании
3. Как получить доступ к контролу из другого потока
.NET не позволяет обращаться к контролам напрямую из других потоков.
3.1 Простой и неправильный способ
Отменяем проверку, из какого потока используется контрол
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
Для одного раза может и сработать, но делать так крайне не рекомендуется.
3.2 Использование методов Invoke/BeginInvoke
Эти методы выполняют указанные делегаты в том потоке, в котором контрол был создан.
Invoke вызывает делегат синхронно, BeginInvoke – асинхронно.
Чтобы определить, требуется ли Invoke используйте свойство InvokeRequired.
Например, объявляем делегат
delegate void Del(string text);
и вызываем Invoke
textBox1.Invoke(new Del((s) => textBox1.Text = s), "newText");
Вместо объявления новых делегатов можно использовать готовые, Action или Func
Пример готового, потоко-безопасного метода
void SetTextSafe(string newText)
{
if (textBox1.InvokeRequired) textBox1.Invoke(new Action<string>((s) => textBox1.Text = s), newText);
else textBox1.Text = newText;
}
4. Как динамически добавить/удалить контрол.
4.1 Добавление
Пример динамического создания кнопки:
System.Windows.Forms.Button button1 = new System.Windows.Forms.Button(); // создаем контрол button1.Location = new System.Drawing.Point(101, 50); // устанавливаем необходимые свойства button1.Name = "button1"; button1.Size = new System.Drawing.Size(75, 23); button1.TabIndex = 0; button1.Text = "button1"; button1.UseVisualStyleBackColor = true; button1.Click += new System.EventHandler(button1_Click); // button1_Click - функция обработчик события нажатия на кнопку Controls.Add(button1); // добавляем на форму
Если непонятно как создать другие контролы – откройте функцию InitializeComponent, которая находится в конструкторе вашей формы. Это функция – код генерируемый дизайнером, посмотрите, как дизайнер создает тот или иной компонент и скопируйте код.
4.2 Удаление
Controls.Remove(button1); button1.Dispose();
5. Как создать массив контролов.
Точно также, как обычный массив
TextBox[] tb = new TextBox[10];
for (int i = 0; i < tb.Length; i++)
{
tb[i] = new System.Windows.Forms.TextBox();
tb[i].Location = new System.Drawing.Point(101, 50 + i * 30);
tb[i].Name = "textBox" + i.ToString();
tb[i].Size = new System.Drawing.Size(75, 23);
tb[i].TabIndex = i;
tb[i].Text = "textBox" + i.ToString();
Controls.Add(tb[i]);
}
Теперь получить доступ к конкретному текстбоксу можно по индексу:
tb[2].Text = "newText";
6. Как получить доступ к контролу по имени.
(Controls["textBox1"] as TextBox).Text = "newText";
7. Как пройтись по всем однотипным котролам.
//Пример обхода всех TextBoxов
foreach (Control control in Controls)
{
TextBox tb = control as TextBox;
if (tb != null)
{
tb.Text = "Text";
}
}