Ответы на 7 самых частых вопроса по WinForms
Дата публикации: 13-05-2011 | Автор: MelfisFettel | Рубрика: C#
Честно говоря это не моя статья. Ни в коем случае не претендую на авторство и если узнаю чья это статья то размещу активную ссылку на нее. А копаясь в тоннах разного материала на своем компе, нашел у себя в папочке с хламом эту статью. Тут как указано в заголовке статьи и правда ответ на семь самых частых вопроса по WinForms C#. Эта заметочка мне частенько помогала.
1. Как создать вторую форму
Любая форма представляет из себя класс, унаследованный от Form.
Экземпляр главной формы создается в файле Program.cs по умолчанию.
Код C#
1 2 3 4 5 6 7 8 9 10 11 12 13 |
namespace NS { static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); // <- вот тут } } } |
namespace NS { static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); // <- вот тут } } }
Чтобы отобразить вторую форму, надо создать экземпляр этого класса (Form2), например в обработчике события главной
Код C#
1 2 3 4 5 6 |
private void button1_Click(object sender, EventArgs e) { Form2 f = new Form2(); // создаем f.ShowDialog(); // показываем f.Show() // или так } |
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
Код C#
1 2 3 4 |
Form2 f = new Form2(); f.ShowDialog(); this.textBox1.Text = f.textBox1.Text; |
Form2 f = new Form2(); f.ShowDialog(); this.textBox1.Text = f.textBox1.Text;
+ Самый быстрый в реализации и удобный способ
- Противоречит всем основам ООП
- Возможна передача только из более поздней формы в более раннюю
- Форма f показывается только с использованием ShowDialog(), т.е. в первую форму управление вернется только по закрытию второй. Избежать этого можно, сохранив ссылку на вторую форму в поле первой формы
2.2 Использование открытого свойства/метода. Способ очень похож на первый
В классе Form2 определяем свойство (или метод)
Код C#
1 2 3 4 5 6 7 |
public string Data { get { return textBox1.Text; } } |
public string Data { get { return textBox1.Text; } }
В любом месте Form1
Код C#
1 2 3 |
Form2 f = new Form2(); f.ShowDialog(); this.textBox1.Text = f.Data; |
Form2 f = new Form2(); f.ShowDialog(); this.textBox1.Text = f.Data;
+ Противоречит не всем основам ООП
- Минусы те же
2.3 Передача данных в конструктор Form2
Изменяем конструктор Form2
Код C#
1 2 3 4 5 6 7 8 |
public Form2(string data) { InitializeComponent(); //Обрабатываем данные //Или записываем их в поле this.data = data; } string data; |
public Form2(string data) { InitializeComponent(); //Обрабатываем данные //Или записываем их в поле this.data = data; } string data;
А создаем форму в любом месте Form1 так:
Код C#
1 2 3 |
Form2 f = new Form2(this.textBox1.Text); f.ShowDialog(); //Или f.Show(); |
Form2 f = new Form2(this.textBox1.Text); f.ShowDialog(); //Или f.Show();
+ Простой в реализации способ
+ Не нарушает ООП
- Возможна передача только из более ранней формы в более позднюю
2.4 Передача ссылки в конструктор
Изменяем конструктор Form2
Код C#
1 2 3 4 5 6 7 |
public Form2(Form1 f1) { InitializeComponent(); //Обрабатываем данные //Или записываем их в поле string s = f1.textBox1.Text; } |
public Form2(Form1 f1) { InitializeComponent(); //Обрабатываем данные //Или записываем их в поле string s = f1.textBox1.Text; }
А создаем форму в любом месте Form1 так, т.е. передаем ей ссылку на первую форму
Код C#
1 2 3 |
Form2 f = new Form2(this); f.ShowDialog(); //Или f.Show(); |
Form2 f = new Form2(this); f.ShowDialog(); //Или f.Show();
+ Доступ ко всем открытым полям/функциям первой формы
+ Передача данных возможна в обе стороны
- Нарушает ООП
2.5 Используем свойство «родитель»
При создании второй формы устанавливаем владельца
Код C#
1 2 3 |
Form2 f = new Form2(); f.Owner = this; f.ShowDialog(); |
Form2 f = new Form2(); f.Owner = this; f.ShowDialog();
Во второй форме определяем владельца
Код C#
1 2 3 4 5 6 |
Form1 main = this.Owner as Form1; if(main != null) { string s = main.textBox1.Text; main.textBox1.Text = "OK"; } |
Form1 main = this.Owner as Form1; if(main != null) { string s = main.textBox1.Text; main.textBox1.Text = "OK"; }
+ Доступ ко всем открытым полям/функциям первой формы
+ Передача данных возможна в обе стороны
+ Не нарушает ООП
2.6 Используем отдельный класс
Создаем отдельный класс, лучше статический, в основном namespace, т.е. например в файле Program.cs
Код C#
1 2 3 4 |
static class Data { public static string Value { get; set; } } |
static class Data { public static string Value { get; set; } }
Его открытые свойства/методы доступны из любой формы.
Код C#
1 |
Data.Value = "111"; |
Data.Value = "111";
+ Самый удобный способ, когда данные активно используются несколькими формами.
2.7 Использование функций обратного вызова
2.7.1 Передача метода в конструктор
Создаем в основном namespace делегат
Код C#
1 |
public delegate void MyDelegate(string data); |
public delegate void MyDelegate(string data);
В Form1 создаем метод, который будет обрабатывать принятые данные
Код C#
1 2 3 4 |
void func(string param) { // обработка } |
void func(string param) { // обработка }
Создаем вторую форму так:
Код C#
1 2 |
Form2 f = new Form2(new MyDelegate(GetData)); f.ShowDialog(); |
Form2 f = new Form2(new MyDelegate(GetData)); f.ShowDialog();
При этом изменяем конструктор второй формы, чтобы он принимал делегат
Код C#
1 2 3 4 5 6 |
MyDelegate d; public Form2(MyDelegate sender) { InitializeComponent(); d= sender; } |
MyDelegate d; public Form2(MyDelegate sender) { InitializeComponent(); d= sender; }
И в любой момент отправляем данные
Код C#
1 |
d(textBox1.Text); |
d(textBox1.Text);
Полный код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//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); } |
//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); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
//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 + "!"); } } } |
//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 + "!"); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//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); } } } |
//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 отдельный класс
Код C#
1 2 3 4 5 |
public static class Data { public delegate void MyEvent(string data); public static MyEvent EventHandler; } |
public static class Data { public delegate void MyEvent(string data); public static MyEvent EventHandler; }
В первой форме добавляем обработчик
Код C#
1 2 3 4 |
void func(string param) { MessageBox.Show(param); } |
void func(string param) { MessageBox.Show(param); }
и инициализируем EventHandler
Код C#
1 |
Data.EventHandler = new Data.MyEvent(func); |
Data.EventHandler = new Data.MyEvent(func);
Вторую форму создаем обычным способом и вызываем из нее
Код C#
1 |
Data.EventHandler(textBox1.Text); |
Data.EventHandler(textBox1.Text);
Полный код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//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; } } |
//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; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//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 + "!"); } } } |
//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 + "!"); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//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); } } } |
//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 Простой и неправильный способ
Отменяем проверку, из какого потока используется контрол
Код C#
1 |
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false; |
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
Для одного раза может и сработать, но делать так крайне не рекомендуется.
3.2 Использование методов Invoke/BeginInvoke
Эти методы выполняют указанные делегаты в том потоке, в котором контрол был создан.
Invoke вызывает делегат синхронно, BeginInvoke — асинхронно.
Чтобы определить, требуется ли Invoke используйте свойство InvokeRequired.
Например, объявляем делегат
Код C#
1 |
delegate void Del(string text); |
delegate void Del(string text);
и вызываем Invoke
Код C#
1 |
textBox1.Invoke(new Del((s) => textBox1.Text = s), "newText"); |
textBox1.Invoke(new Del((s) => textBox1.Text = s), "newText");
Вместо объявления новых делегатов можно использовать готовые, Action или Func
Пример готового, потоко-безопасного метода:
Код C#
1 2 3 4 5 |
void SetTextSafe(string newText) { if (textBox1.InvokeRequired) textBox1.Invoke(new Action<string>((s) => textBox1.Text = s), newText); else textBox1.Text = newText; } |
void SetTextSafe(string newText) { if (textBox1.InvokeRequired) textBox1.Invoke(new Action<string>((s) => textBox1.Text = s), newText); else textBox1.Text = newText; }
4. Как динамически добавить/удалить контрол.
4.1 Добавление
Пример динамического создания кнопки:
Код C#
1 2 3 4 5 6 7 8 9 |
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); // добавляем на форму |
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 Удаление
Код C#
1 2 |
Controls.Remove(button1); button1.Dispose(); |
Controls.Remove(button1); button1.Dispose();
5. Как создать массив контролов.
Точно также, как обычный массив
Код C#
1 2 3 4 5 6 7 8 9 10 11 |
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]); } |
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]); }
Теперь получить доступ к конкретному текстбоксу можно по индексу:
Код C#
1 |
tb[2].Text = "newText"; |
tb[2].Text = "newText";
6. Как получить доступ к контролу по имени.
Код C#
1 |
(Controls["textBox1"] as TextBox).Text = "newText"; |
(Controls["textBox1"] as TextBox).Text = "newText";
7. Как пройтись по всем однотипным котролам.
Код C#
1 2 3 4 5 6 7 8 9 |
//Пример обхода всех TextBoxов foreach (Control control in Controls) { TextBox tb = control as TextBox; if (tb != null) { tb.Text = "Text"; } } |
//Пример обхода всех TextBoxов foreach (Control control in Controls) { TextBox tb = control as TextBox; if (tb != null) { tb.Text = "Text"; } }
это статья из cyberforum.ru, вот она:
http://www.cyberforum.ru/windows-forms/thread110436.html