Ответы на 7 самых частых вопроса по WinForms

Дата публикации: 13-05-2011 | Автор: MelfisFettel | Рубрика: C#

Visual 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";
    }
}
Понравилась статья? Расскажи друзьям:


Комментариев (1)

это статья из cyberforum.ru, вот она:
http://www.cyberforum.ru/windows-forms/thread110436.html

Обсудить