Обработка событий в windows forms c

Последнее обновление: 31.10.2015

Последнее обновление: 31.10.2015

Для взаимодействия с пользователем в Windows Forms используется механизм событий. События в Windows Forms представляют стандартные события на C#, только
применяемые к визуальным компонентам и подчиняются тем же правилам, что события в C#. Но создание обработчиков событий в Windows Forms все же
имеет некоторые особенности.

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

События в Windows Forms

Чтобы добавить обработчик, можно просто два раза нажать по пустому полю рядом с названием события, и после этого Visual Studio
автоматически сгенерирует обработчик события. Например, нажмем для создания обработчика для события Load:

И в этом поле отобразится название метода обработчика события Load. По умолчанию он называется Form1_Load.

Если мы перейдем в файл кода формы Form1.cs, то увидим автосгенерированный метод Form1_Load:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }
}

И при каждой загрузке формы будет срабатывать код в обработчике Form1_Load.

Как правило, большинство обработчиков различных визуальных компонентов имеют два параметра: sender — объект, инициировавший событие,
и аргумент, хранящий информацию о событии (в данном случае EventArgs e).

Но это только обработчик. Добавление же обработчика, созданного таким образом, производится в файле Form1.Designer.cs:

namespace HelloApp
{
    partial class Form1
    {
        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        private void InitializeComponent()
        {
            this.SuspendLayout();

            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(284, 261);
            this.Name = "Form1";
			// добавление обработчика 
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
        }
    }
}

Для добавления обработчика используется стандартный синтаксис C#: this.Load += new System.EventHandler(this.Form1_Load)

Поэтому если мы захотим удалить созданный подобным образом обработчик, то нам надо не только удалить метод из кода формы в Form1.cs, но и
удалить добавление обработчика в этом файле.

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

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 Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.Load += LoadEvent;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void LoadEvent(object sender, EventArgs e)
        {
            this.BackColor = Color.Yellow;
        }
    }
}

Кроме ранее созданного обработчика Form1_Load здесь также добавлен другой обработчик загрузки формы: this.Load += LoadEvent;, который
устанавливает в качестве фона желтый цвет.

GUI
управляется событиями. Приложение
выполняет действия в ответ на события,
вызванные пользователем, например, на
щелчок кнопкой мыши или выбор пункта
меню. В Windows Forms применяется модель
обработки событий .NET, в которой делегаты
используются для того, чтобы связать
события с обрабатывающими их методами.
В классах Windows Forms используются групповые
делегаты. Групповой
делегат содержит список связанных с
ним методов
.
Когда в приложении происходит событие,
управляющий элемент возбуждает событие,
вызвав делегат для этого события, который
вызывает связанные с ним методы. Для
того чтобы добавить делегат к событию
используется перегруженный оператор
+=.
Например:

this.MouseClick
+= new
MouseEventHandler(this.Form1_MouseClick);

Объявление
обработчика для этого события:

private
void Form1_MouseClick(object sender, MouseEventArgs e)

{
}

В
качестве параметра обработчик событий
получает объект класса МоuseEventArgs
(производный от класса EventArgs). Свойства
этого объекта содержат информацию,
связанную с данным событием.

  • Button
    (Кнопка) определяет, какая кнопка была
    нажата,

  • Clicks
    (Щелчки) определяет, сколько раз была
    нажата и отпущена кнопка,

  • Свойство
    Delta (Дельта) является счетчиком оборотов
    колесика мыши;

  • X
    и Y — координаты точки, в которой
    находился указатель в момент нажатия
    кнопки мыши

Внесем
изменения в FirstForm,
чтобы при щелчке кнопкой мыши строка с
приветствием перемещалась на место
щелчка.

Программа
1
: Отображает
перемещение приветствия по щелчку мыши.

public
partial class Form1 : Form {

float
x, y; // координаты

Brush
pStdBrush; //
Кисть

Graphics
poGraphics;

public
Form1() {

InitializeComponent();

x=10;
y=20;

pStdBrush
= new SolidBrush(Color.Black);

poGraphics
= this.CreateGraphics();

this.Text
= «Программа
1»;

this.Show();

poGraphics.DrawString(«Hello,
Window Forms», this.Font, pStdBrush, x, y);

}

private
void Form1_MouseClick(object sender, MouseEventArgs e) {

//
координаты
точки
щелчка
мыши

x
= (float)e.X;
y
= (float)e.Y;

poGraphics.DrawString(«Hello,
Window Forms», this.Font, pStdBrush, x, y);

}

}

Параметры
метода
DrawString:

  • выводимая
    строка;

  • шрифт
    (Font— свойство класса Form, которое
    определяет шрифт, по умолчанию применяемый
    для вывода текста в форму);

  • используемая
    кисть;

  • координаты
    в пикселях.

Метод
Form1_MouseClick
устанавливает координаты текста, х и
у, равными координатам точки, в которой
находился указатель в момент щелчка.

Несколько
обработчиков для события.
Реализуем
два обработчика события MouseClick.
Второй обработчик по щелчку кнопкой
мыши просто отображает окно сообщения.
Метод ShowClick
подключается к событию в ручную аналогично
методу Form1_MouseClick
в файле Form1.Designer.cs.

Программа
2
: Два
обработчика событий для MouseClick

public
partial
class
Form1
: Form
{

.
. .

private
void Form1_MouseClick(object sender, MouseEventArgs e) {

x
= (float)e.X; y = (float)e.Y;

poGraphics.DrawString(«Hello,
Window Forms», this.Font, pStdBrush, x, y);

}

void
ShowClick (object pSender, MouseEventArgs e)

MessageBox.Show(«Mouse
clicked!!'»);

}

Введем
в пример обработку события KeyPress, а также
покажем, как в событии MouseDown различать,
какая кнопка была нажата, левая или
правая (программа
3
).

Обработка
событий от правой и левой кнопкои мыши.
Для того
чтобы определить, какая кнопка мыши
была нажата используем свойство Button
параметра MouseEventArgs. Перепишем методы
обработчика событий:

private
void Form1_MouseClick(object sender, MouseEventArgs e) {

//
если
левая
кнопка

if
(e.Button == System.Windows.Forms.MouseButtons.Left) {

x
= (float)e.X; y = (float)e.Y;

poGraphics.DrawString(«Hello,
Window Forms», this.Font, pStdBrush, x, y);

}

}

void
ShowClick (object pSender, MouseEventArgs e) {

//
если
правая
кнопка

if
(e.Button == System.Windows.Forms.MouseButtons.Right)

MessageBox.Show(«Mouse
clicked!!'»);

}

Событие
Keypress.
При
нажатии пользователем на клавишу, в
конец строки приветствия будет добавлен
соответствующий символ. Вместо класса
String используется класс StringBuilder, который
более эффективен в этой ситуации.

public
partial class Form1 : Form {

StringBuilder
pStr;

String
s;

public
Form1() {

.
. .

pStr
= new StringBuilder(«Hello, Window Forms»);

s
= pStr.ToString();

poGraphics.DrawString(s,
this.Font, pStdBrush, x, y);

}

private
void Form1_KeyPress(object sender, KeyPressEventArgs e)

{
pStr.Append(e.KeyChar); // Добавляем
в
конец

s
= pStr.ToString();

poGraphics.DrawString(s,
this.Font, pStdBrush, x, y);

}

}

Программа
4
: Создадим
шуточную программу, представляющую
собой диалоговое окно с двумя кнопками.
Назовем его SocOpros. Из окна Toolbox перетаскиваем
на форму две кнопки Button и надпись Label и
устанавливаем следующие свойства
элементов управления и формы (табл.
3.4):

Таблица
3.4
— Описание формы приложения

Форма,
свойства

Значение

FormBorderStyle

Fixed3D

Icon


Путь
С:Program FilesMicrosoft Visual
Studio 8 Common7 VS2008ImageLibraryicons….

Text

Социологический
опрос

Label1,
свойство

Значение

Bold

True

Text

Вы
довольны своей зарплатой?

Button1,
свойство

Значение

Name

Btnyes

Text

Да

Button2,
свойство

Значение

Name

Btnno

Text

Нет

Щелкаем
дважды по кнопке «Да». В обработчике
этой кнопки вставляем следующий код:

void
btnyes_Click(object sender, EventArgs
e){

MessageBox.Show(«Мы
и не сомневались, что Вы так думаете!»);

}

Выделяем
кнопку «Нет». Открываем окно
Properties. Переключаемся в окно событий и
дважды щелкаем в поле MouseMove.

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

private
void Btnno_MouseMove(object sender, MouseEventArgs e) {
Btnno.Top -= e.Y; Btnno.Left += e.X;

if
(Btnno.Top < -10 || Btnno.Top > 100) Btnno.Top = 60;

if
(Btnno.Left < -80 || Btnno.Left > 250) Btnno.Left = 120;

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

В платформе .NET, как и в Win32, для информирования о возникновении какого-либо состояния или о действии используются события, или иногда их еще называют сообщения (по-английски: events). Например, в ответ на изменение положения окна оно генерирует событие определенного класса, которое мы можем перехватить.

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

С помощью визуального дизайнера Visual Studio создание обработчиков событий превращается в тривиальную задачу. На рис. 5.8 показана панель Properties в режиме просмотра событий. Чтобы увидеть что-то подобное, нужно выделить компонент, событие которого вы хотите поймать, и нажать кнопку Events в панели Properties (на рис. 5.8 эта кнопка обведена кружком). Чтобы вернуться обратно к просмотру свойств, надо щелкнуть по кнопке Properties, которая находится левее.

Панель Properties 
при просмотре событий

Рис. 5.8. Панель Properties
при просмотре событий

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

Давайте создадим обработчик события MouseClick. Выделите форму, перейдите
в панели Properties в режим просмотра событий Events и щелкните двойным щелчком напротив события. Будет создан метод Form1_MouseClick():

   private void Form1_MouseClick(object sender, MouseEventArgs e)
   {
     MessageBox.Show("Клик");
   }

Я здесь добавил внутрь метода обработки события вызов статического метода Show() класса MessageBox. Этот метод отображает на рабочем столе диалоговое окно с сообщением, которое вы передали в качестве параметра. В нашем случае каждый раз, когда вы щелкнете по форме, будет появляться сообщение: Клик.

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

  • Load — загрузка;
  • Activate — активация;
  • VisibleChanged — изменилось свойство Visible.
  • А при закрытии формы генерируются следующие события:
  • Deactivated — деактивировано;
  • Closing — закрытие формы (можно отменить закрытие);
  • Close — форма закрыта, и назад дороги нет.

Событие Load генерируется, когда вы впервые вызываете метод Show() для отображения формы. Посмотрим на следующий пример:

   MyForm form = new MyForm();
   form.Show();   // отобразить форму
   form.Hide();   // спрятать с помощью Hide()
   form.Show();   // Отобразить снова

Событие Load будет сгенерировано только при первом вызове метода Show(), потому что в этот момент начнет происходить загрузка формы. Когда мы вызываем метод Hide(), то форма остается загруженной, просто прячется с экрана. Следующий вызов метода Show() только изменяет видимость окна, а загрузки не произойдет, поэтому и событие Load больше генерироваться не станет.

Очень часто у вас будут возникать казусы со случайным созданием событий. Например, если щелкнуть двойным щелчком по компоненту в визуальном дизайнере, то будет создан обработчик события по умолчанию для этого компонента. Так, для кнопки событием по умолчанию является Click, и если вы случайно щелкнете двойным щелчком по компоненту в визуальном дизайнере, то будет создан такой обработчик события. А если вы не хотели его создавать? Оставлять заготовку
метода в коде? Наверное, лучше, все же, убрать обработчик события, чтобы он не мешал. Как это сделать?

Существует несколько вариантов:

  • Выделите компонент в визуальном дизайнере и перейдите в режим Events в панели свойств. Напротив события удалите в поле название метода, созданного для обработчика события. Визуальный редактор удалит регистрацию события, которую он автоматически добавил в свой метод InitializeComponent(). Если
    в обработчике события не было кода, то заготовка для метода исчезнет и из кода.
  • Если обработчик события содержит код, но он уже не нужен, то можно сначала удалить код из обработчика события, а потом выполнить действия из предыдущего пункта.
  • Если обработчик события содержит код, то можно сначала удалить имя обработчика события в режиме Events панели свойств, а потом безболезненно удалить код метода.

Если вы создали обработчик события и тут же удалили метод в редакторе кода,
то при этом среда разработки не удалит регистрацию события в методе InitializeComponent(). Это придется делать вручную. Как это сделать безболезненно? Давайте посмотрим на примере.

Создайте новое приложение и поместите на его форму кнопку. Щелкните по кнопке двойным щелчком, и среда разработки переключит вас в редактор кода с созданным для обработки события методом:

private void button1_Click(object sender, EventArgs e)
{
}

Удалите эту заготовку кода из редактора и попробуйте скомпилировать проект. Внизу окна появится сообщение об ошибке (рис. 5.9). В этой ошибке компилятор сообщает нам, что обработчик события не найден. Щелкните двойным щелчком по ошибке, и откроется вкладка с файлом (Form1.Designer.cs), где найдена ошибка, и

будет выделена строка кода, которую добавил визуальный редактор для регистрации события. События — это отдельная тема, которая будет рассмотрена в главе 10. А сейчас нужно только понимать, что для того, чтобы избавиться от ошибки, нужно удалить строку, которую выделил нам редактор. Так вы вручную удалите регистрацию, и проект откомпилируется без проблем.

 Сообщение об ошибке, что обработчик события не найден

Рис. 5.9. Сообщение об ошибке, что обработчик события не найден

Это бесплатная глава книги Библия C#. В новом издании эта глава переписана с учетом универсальных при-ложений Windows, а старая версия главы, которая не потеряла еще своей актуаль-ности стала бесплатной и доступной всем.

Все исходные коды главы 5 Библии C#

Содержание

  1. Python
    1. tkinter Стандратный модуль для создания приложений с GUI интерфейсом.
  2. VBA
    1. VBA GUI в среде MS Excel.
  3. HTML
    1. HTML book Обзор GUI в HTML.
  4. Pascal
    1. Windows Forms Интерфейс (API) для создания GUI-приложений.

Windows Forms — фреймворк для работы с формами.

Общая структура программы[править]

Любая программа, использующая Wondows Forms может иметь следующий вид:

{$apptype windows}
{$reference 'System.Windows.Forms.dll'}
{$reference 'System.Drawing.dll'}
 
uses
  System.Windows.Forms,
  System.Drawing;
  
var
  MainForm: System.Windows.Forms.Form;

begin
  MainForm := new Form;
  Application.Run(MainForm);
end.

MainForm — главная форма.

Основные классы[править]

Windows Forms содержит следующие классы:

  1. System.Windows.Forms.Button или Button (кнопка)
  2. System.Windows.Forms.Label или Label (метка)
  3. System.Windows.Forms.CheckBox или CheckBox (флажок)
  4. System.Windows.Forms.RadioButton или RadioButton (радио-кнопка)
  5. System.Windows.Forms.TrackBar или TrackBar (ползунок)
  6. System.Windows.Forms.ListBox или ListBox (список)
  7. System.Windows.Forms.ComboBox или ComboBox (выпадающий список)
  8. System.Windows.Forms.Form или Form (форма)
  9. System.Windows.Forms.GroupBox или GroupBox (фрейм)
  10. System.Windows.Forms.SplitContainer или SplitContainer (элемент разделения окна)
  11. System.Windows.Forms.MenuStrip или MenuStrip (главное меню)
  12. System.Windows.Forms.ToolStripMenuItem или ToolStripMenuItem (подменю)

Button[править]

System.Windows.Forms.Button — класс кнопки. Синтаксис ее создания:

name — имя кнопки.

Свойство Значение
Width Ширина кнопки.
Height Высота кнопки.
Text Текст на кнопке.
BackColor Цвет фона кнопки.
ForeColor Цвет текста кнопки.
Location Позиция кнопки на форме.

В качестве значения должна быть точка System.Drawing.Point.

AutoSize Будет ли меняться размер кнопки, подгоняясь под размер содержимого, или будет отображаться лишь та часть содержимого, умещающаяся на кнопке.
Parent Родительский виджет.
Visible Видна ли кнопка.
Событие Значение
Click Хранит ссылку на процедуру, которая выполниться при нажатии на кнопку.

Для установки его значения используйте вместо := +=.

Label[править]

System.Windows.Forms.Label — класс метки. Синтаксис ее создания:

name — имя метки.

Свойство Значение
Width Ширина метки.
Height Высота метки.
Text Текст на метки.
BackColor Цвет фона метки.
ForeColor Цвет текста метки.
Location Позиция метки на форме.
AutoSize Будет ли меняться размер метки, подгоняясь под размер содержимого, или будет отображаться лишь та часть содержимого, умещающаяся на метке.
Parent Родительский виджет.
Visible Видна ли метка.

CheckBox[править]

System.Windows.Forms.CheckBox — класс флажка. Синтаксис его создания:

name — имя флажка.

Свойство Значение
Width Ширина флажка.
Height Высота флажка.
Text Текст на флажка.
BackColor Цвет фона флажка.
ForeColor Цвет текста флажка.
Location Позиция флажка форме.
AutoSize Будет ли меняться размер флажка, подгоняясь под размер содержимого, или будет отображаться лишь та часть содержимого, умещающаяся на флажка.
Parent Родительский виджет.
Visible Виден ли флажок.
Checked Определяет установлен ли флажок или нет.

RadioBox[править]

System.Windows.Forms.RadioBox- класс радио-кнопки. Синтаксис ее создания:

name — имя радио-кнопки.

Свойство Значение
Width Ширина радио-кнопки.
Height Высота радио-кнопки.
Text Текст на радио-кнопки.
BackColor Цвет фона радио-кнопки.
ForeColor Цвет текста радио-кнопки.
Location Позиция радио-кнопки форме.
AutoSize Будет ли меняться размер радио-кнопки, подгоняясь под размер содержимого, или будет отображаться лишь та часть содержимого, умещающаяся на радио-кнопке.
Parent Родительский виджет.
Visible Видна ли радио-кнопка.
Checked Определяет установлена ли радио-кнопка или нет.

TrackBar[править]

System.Windows.Forms.TrackBar — класс ползунка. Синтаксис его создания:

name — имя ползунка.

Свойство Значение
Width Ширина ползунка.
Height Ширина ползунка.
Location Позиция ползунка на форме.
Parent Родительский виджет.
Visible Виден ли ползунок.
Minimum Минимальное значение ползунка.
Maximum Максимальное значение ползунка.
Value Текущее значение ползунка.
Orientation Ориентация ползунка.

  • System.Windows.Forms.Orientation.Horizontal — горизонтальная
  • System.Windows.Forms.Orientation.Vertical — вертикальная
TickStyle Контролирует как отображаются деления.

  • System.Windows.Forms.TickStyle.Both — с двух сторон
  • System.Windows.Forms.TickStyle.BottomRight — деления либо снизу (для горизонтального ползунка) или справа (для вертикального полузнка)
  • System.Windows.Forms.TickStyle.TopLeft — деления либо сверху (для горизонтального ползунка) или слева (для вертикального полузнка)
  • System.Windows.Forms.TickStyle.None — не отображаются
TickFrequency Расстояние между делениями.

ListBox[править]

System.Windows.Forms.ListBox- класс списка. Синтаксис его создания:

name — имя списка.

Свойство Значение
Width Ширина списка.
Height Высота списка.
Location Позиция списка на форме.
Parent Родительский виджет.
Visible Виден ли список.
ItemHeight Высота элемента списка.
Items.Count Количество элементов списка.
Items.Item[k] K-ый элемент списка.
IntegralHeight Указывает будет ли подгоняться размер списка под размер элементов, чтобы был видны названия всех элементов полностью.
Событие Описание
Click Хранит ссылку на процедуру, которая выполнится при щелчке по списку.
SelectedIndexChanged Хранит ссылку на процедуру, которая выполнится при смене выбранного элемента списка.

Ниже a — список.

Процедура Значение
a.Items.Add(t) Добавляет в список элемент с текстом t.
a.Items.Clear Очищает список.

ComboBox[править]

System.Windows.Forms.ComboBox — класс выпадающего списка. Для его создания пишите:

name — имя выпадающего списка.

Свойство Значение
Width Ширина выпадающего списка.
Height Высота выпадающего списка.
Parent Родительский виджет.
Visible Виден ли выпадающий список.
Count Количество элементов в выпадающем списке.
SelectedIndex Индекс выбранного элемента выпадающего списка.
SelectedItem Выбранный элемент выпадающего списка.
Items.Item[k] K-ый элемент выпадающего списка.
IntegralHeight Указывает будет ли подгоняться размер выпадающего списка под размер элементов, чтобы был видны названия всех элементов полностью.
Событие Описание
Click Хранит ссылку на процедуру, которая выполнится при щелчке по выпадающему списку.
SelectedIndexChanged Хранит ссылку на процедуру, которая выполнится при смене выбранного элемента выпадающего списка.

Ниже a — выпадающий список.

Функция Описание
a.Items.Add Добавляет в выпадающий список элемент.
a.Items.Clear Удаляет все элементы выпадающего списка.

GroupBox[править]

System.Windows.Forms.GroupBox- класс фрейма. Синтаксис его создания:

name — имя кнопки.

Свойство Значение
Width Ширина фрейма.
Height Высота фрейма.
Text Текст на в заголовке фрейма.
Location Позиция фрейма на форме.

В качестве значения должна быть точка System.Drawing.Point.

AutoSize Будет ли меняться размер фрейма, подгоняясь под размер содержимого, или будет отображаться лишь та часть содержимого, умещающаяся на кнопке.
Parent Родительский виджет.
Visible Виден ли фрейм.

SplitContainer[править]

System.Windows.Forms.SplitContainer — класс элемента разделения окна. Синтаксис его создания:

name := new SplitContainer();

name — имя элемента разделения окна.

Свойство Значение
Width Ширина элемента разделения окна.
Height Высота элемента разделения окна.
Location Позиция элемента разделения окна на форме.

В качестве значения должна быть точка System.Drawing.Point.

AutoSize Будет ли меняться размер элемента разделения окна, подгоняясь под размер содержимого, или будет отображаться лишь та часть содержимого, умещающаяся на элементе разделения окна.
Visible Виден ли элемент разделения окна.
Orientation Ориентация элемента разделения окна.

  • System.Windows.Forms.Orientation.Horizontal — горизонтальная
  • System.Windows.Forms.Orientation.Vertical — вертикальная
Parent Родительский виджет.
Panel1 Имя виджета, входящего в левую или верхнюю часть элемента разделения окна.
Panel2 Имя виджета, входящего в правую или нижнюю часть элемента разделения окна.

[править]

System.Windows.Forms.MenuStrip — класс главного меню. Синтаксис его создания:

name := new MenuStrip ();

name — имя главного меню.

Свойство Значение
BackColor Цвет фона главного меню.
ForeColor Цвет текста меню.
GripStyle Видим ли объект для перемещения меню, находящийся слева.

  • объект перемещения меню спрятан — System.Windows.Forms.ToolStripGripStyle.Hidden
  • объект перемещения меню виден- System.Windows.Forms.ToolStripGripStyle.Visisble

Ниже a — главное меню.

Процедура Значение
a.Items.Add(k) Добавляет подменю k в главное меню.

[править]

System.Windows.Forms.ToolStripMenuItem — класс подменю. Синтаксис его создания:

name := new ToolStripMenuItem ();

name — имя подменю.

Свойство Значение
BackColor Цвет фона заголовка подменю.
ForeColor Цвет текста заголовка подменю.

Ниже b — подменю.

Процедура Значение
b.DropDownItems.Add(t,i,act) Добавляет пункт в подменю b.

  • t — текст, отображаемый на пункте подменю; i — иконка пункта подменю (чтобы ее не было пишите nil); act — процедура, выполняющаяся при нажатии на этот пункт меню.
  • иконка зугружается следующим образом: new System.Drawing.Bitmap(GetResourceStream(путь_к_изображению))

Форма[править]

System.Windows.Forms.Form — класс формы. Общий синтаксис ее создания:

Свойство Описане
Text Заголовок формы.

Ниже a — форма.

Свойство Описане
a.Controls.Add(виджет) Добавляет виджет на форму.

Курсор[править]

Cursor — объект курсора в Windows Forms.

Свойство Значение
System.Windows.Forms.Cursor.Position.X Позиция курсора по X.
System.Windows.Forms.Cursor.Position.Y Позиция курсора по Y.

Обработка событий[править]

Любая процедура, являющаяся обработчиком события должна иметь вид:

procedure p(sender:object; args:System.EventArgs);
begin
   //тело процедуры
end;

p — имя процедуры.

Стили[править]

Подключить визуальные стили для более красивого отображения виджетов можно так:

Application.EnableVisualStyles;

Примеры программ[править]

  • Вывод сообщения по нажатию кнопки:
{$reference 'System.Windows.Forms.dll'}
{$reference 'System.Drawing.dll'}
  
uses System, System.Windows.Forms;
 
var
  f : Form;
  btn : Button;
 
procedure ButtonClick(sender: object; e: EventArgs);
begin
  MessageBox.Show('Hello world!');
end;    
 
begin
  f := new Form;
  btn := new Button;
  btn.Text := 'Click me';
  btn.Click += ButtonClick;
  f.Controls.Add(btn);
  Application.Run(f);
end.

События в Windows-приложениях

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

Откройте снова приложение FirstForm. Из окна Toolbox перетащите элемент управления Button на форму. Дважды щелкните на кнопке button1. В коде найдите область Windows Form Designer generated code. В таблице 1.3 сравниваются листинги приложений Event и FirstForm c кнопкой.

Таблица
1.3.

Консольное приложение Event Windows-приложение FirstForm
using System;
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace Event
{
//Объявляем делегат Mydelegate
delegate void Mydelegate();
//Создаем класс Button, в котором 
//будет находится событие 
//и метод  для него
class Button
{
// Объявляем событие Sobitie 
// на основе делегата
public event Mydelegate Sobitie;
//Cоздаем метод для события, 
//который просто будет 
//обращаться к событию
public void MetoddlyaSobitiya()
{
  //Можно вставить проверку наличия события. 
  //if (Sobitie !=null)
  Sobitie();
}
class Class1
{
namespace FirstForm
{
	
public class Form1 : System.Windows.Forms.Form
{
  private System.Windows.Forms.Button button1;
	
private System.ComponentModel.Container 
  components = null;
		
public Form1()
{
			
InitializeComponent();
			
}

protected override void Dispose(bool disposing)
{
	if( disposing )
{
	if (components != null) 
{
	components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
	
private void InitializeComponent()
{
// Среда автоматически создает экземпляр 
// button1 класса Button при перетаскивании 
// элемента управления на форму
this.button1 = 
      new System.Windows.Forms.Button();
this.SuspendLayout();
// 
// button1
// 
this.button1.Location = 
      new System.Drawing.Point(104, 144);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
// Среда автоматически привязывает 
// обработчик для события Click экземпляра 
// button1. EventHandler – это делегат.
this.button1.Click += 
 new System.EventHandler(this.button1_Click);
// 
// Form1
// 
this.AutoScaleBaseSize = 
      new System.Drawing.Size(5, 13);
this.ClientSize = 
      new System.Drawing.Size(292, 266);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Fom1";
this.ResumeLayout(false);

}
#endregion
[STAThread]
static void Main(string[] args)
{
 // Создаем экземпляр btn класса Button
 Button btn = new Button();
 //привязываем обработчик для события 
 //Sobitie экземпляра btn.
 //Когда в скобках укажете 
 //Metodobrabotchik, нажмите 
 //дважды клавишу Tab
 btn.Sobitie += 
       new Mydelegate(Metodobrabotchik);
 //Развернутая запись строки выше
 //btn.Sobitie =  btn.Sobitie + 
 //     new Mydelegate(Metodobrabotchik);
 //вызываем метод для события
 btn.MetoddlyaSobitiya();
}
[STAThread]
static void Main() 
{
Application.Run(new Form1());
}
// Создаем метод-обработчик, если среда 
// сгенерировала его сама – 
// добавляем строку вывода.
private static void Metodobrabotchik ()
{
 Console.WriteLine("Произошло событие");
}
}
}
}
// Метод-обработчик для нажатия на кнопку; 
// когда мы щелкаем по элементу управления 
// в режиме дизайна, среда генерирует этот
//метод и курсор оказывается уже здесь
private void button1_Click(object sender, 
           System.EventArgs e)
{
MessageBox.Show("Произошло событие");
}
}
}

Сравнивая листинги, замечаем, что для Windows-приложения First Form не нужно объявлять делегат, событие, метод для обращения к событию и затем вызывать этот метод. Почему же это тогда работает? Дело в том, что среда .NET содержит огромное количество встроенных событий, доступ к которым осуществляется по их названиям. Более того, среда сама привязывает обработчика для события Click (нажатие на кнопку) и нужный метод, используя встроенный делегат EventHandler:

this.button1.Click += new System.EventHandler(this.button1_Click);

Платформа .NET требует точной сигнатуры для любого обработчика событий. button1_Click () и все остальные обработчики событий обязаны выглядеть следующим образом:

void button1_Click (object sender, EventArgs e)//е также может быть производным от EventArgs
{
// код для обработки события
}

Обработчики событий не могут возвращать ничего, кроме void. В них отсутствует точка, которая могла бы служить для возврата значения. Обработчики должны принимать два параметра. Первый параметр является ссылкой на объект, который сгенерировал событие. Второй параметр должен быть ссылкой либо на базовый класс .NET System.EventArgs, либо на производный класс. Класс EventArgs представляет собой общий базовый класс для всех уведомлений о произошедших событиях.

В окне свойств каждого элемента управления на вкладке событий перечислены все доступные события для этого элемента (рис. 1.39).

Вкладка событий элемента button в окне свойств Properties

Рис.
1.39.
Вкладка событий элемента button в окне свойств Properties

Двойной щелчок в поле выбранного свойства перемещает нас в режим дизайна, где уже сгенерированы все объекты для обработки данного события и нам остается только написать код для метода-обработчика. На рис. рис. 1.39 выбрано событие Click, это же событие выбирается по умолчанию при двойном щелчке на элементе управления «кнопка».

События мыши

В Интернете часто встречается шуточная программка, представляющая собой диалоговое окно с двумя кнопками. Для ответа на предлагаемый вопрос следует нажать на одну из двух кнопок, причем вторая кнопка при наведении на нее курсора начинает «убегать» от него. Вы можете встретить реализацию этой шутки, написанную на многих языках — от C до Flash-приложений. Сделаем что-то подобное на C#. Создаем новое Windowsприложение и называем его SocOpros. Из окна Toolbox перетаскиваем на форму две кнопки Button и надпись Label. Устанавливаем следующие свойства элементов управления и формы:

Form1, форма, свойство Значение
FormBorderStyle Fixed3D
Icon ICOПуть E:Program FilesMicrosoft Visual Studio .NET2003Common7GraphicsiconsComputerW95MBX02.ICO
Size 344; 176
Text Социологический опрос
label1, свойство Значение
Size 12
Bold true
Location 32; 28
Size 272; 32
Text Вы довольны своей зарплатой?
Button1, свойство Значение
Name btnyes
Location 67; 92
Text Да
Button2, свойство Значение
Name btnno
Location 195; 92
Text Нет

Щелкаем дважды по кнопке «Да». В обработчике этой кнопки вставляем следующий код:

private void btnyes_Click(object sender, System.EventArgs e)
{
	MessageBox.Show("Мы и не сомневались, что Вы так думаете!");
}

Выделяем кнопку «Нет». Открываем окно Properties. Переключаемся в окно событий и дважды щелкаем в поле MouseMove (рис. 1.40).

Событие MouseMove для кнопки btnno Надпись на информационной панели — "Происходит, когда мышь перемещается"

Рис.
1.40.
Событие MouseMove для кнопки btnno Надпись на информационной панели — «Происходит, когда мышь перемещается»

В обработчике этого события связываем движение мыши с координатами кнопки и устанавливаем координаты кнопки, куда она будет возвращаться, если во время своего движения выйдет за указанную область:

private void btnno_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
		btnno.Top -= e.Y;
		btnno.Left += e.X;
		if (btnno.Top < -10 || btnno.Top > 100)
		btnno.Top = 60;
		if (btnno.Left < -80 || btnno.Left > 250)
		btnno.Left = 120;
}

Запустите приложение. Теперь, при выборе «Да» появляется окно с надписью, а при попытке нажать на кнопку «Нет» она «убегает» (рис. 1.41).

Готовое приложение SocOpros

Рис.
1.41.
Готовое приложение SocOpros

С событиями мыши связано большинство инструментов во многих программах, а для некоторых, например, графических, — это основа всего взаимодействия с пользователем. Другие события мыши — такие как MouseDown, MouseEnter, MouseUp — могут быть использованы для получения необычной реакции на действия пользователя в этом приложении.

На диске, прилагаемом к книге, вы найдете приложение SocOpros (CodeGlava1 SocOpros ).

Written on 18 Июня 2013. Posted in C#.NET

Страница 7 из 7

15. События форм Windows

Формы Windows реализуют свои собственные события, а также обеспечивают обработку событий, возбуждаемых элементами управления, содержащимися внутри формы или внутри контейнерных элементов управления в классе формы. Кроме того, реализация и обработка событий в классах Windows Forms требуют тщательного анализа и даже применения особых шагов с учётом того, что Windows Forms и содержащиеся в них элементы управления проявляют «привязку к потоку» – то есть их свойства может обновлять только код, выполняющийся в том же потоке, который создал форму или элементы управления.

Эти и другие связанные с Windows Forms принципы представлены в данном разделе.

15.1 Различие NET 1.x и 2.0+ — частичные классы

Концепция «частичного класса» была введена в среду разработки .NET версии 2.0. Частичный класс – класс, объявленный с ключевым словом partial, и с частями класса, определенными в двух или более файлах исходного кода. Компилятор извлекает весь исходный код, определяющий частичный класс, из всех файлов, содержащих частичный класс, и выдает один [скомпилированный] класс. То есть частичный класс может располагаться в двух или более файлах исходного кода, но когда приложение компилируется, «части класса» собираются в один класс в выходной сборке.

Преимущества частичных классов включают (1) несколько разработчиков могут работать над разными частями одного и того же класса одновременно, работая с разными файлами исходного кода; и (2) автоматизированные инструменты генерации кода могут писать в один файл исходного кода, в то время как люди-разработчики могут поддерживать свой код в отдельном файле, не беспокоясь, что их изменения впоследствии могут быть переписаны автоматизированным инструментом генерации кода. Это второе преимущество реализовано в проектах Windows Forms, начиная с Visual Studio 2005. Когда вы добавляете новую форму в проект Windows Forms, Visual Studio автоматически создает форму в виде частичного класса, определенного в двух файлах исходного кода. Файл, содержащий код, сгенерированный Visual studio, называется FormName.Designer.cs, тогда как файл, предназначенный для кода разработчика, называется FormName.cs.

Например, если вы заставите Visual Studio 2005 создать форму с именем MainForm, то будут созданы следующие два файла исходного кода:

MainForm.cs – содержит определение частичного класса:

public partial class MainForm : Form  
{
   // разработчики пишут код здесь
}
MainForm.Designer.cs - содержит определение частичного класса:
partial class MainForm
{
   // проектировщик Windows Forms пишет код здесь
}

Когда вы добавляете элементы управления на форму путем использования проектировщика Windows Forms Visual Studio, проектировщик добавляет необходимый код в файл FormName.Designer.cs.

Разработчики не должны непосредственно изменять исходный код в файле FormName.Designer.cs, так как не исключено, что проектировщик перепишет такие изменения. Как правило, весь код разработчика должен быть записан в файле FormName.cs.

.NET 1.x не имеет частичных классов. Весь исходный код – будь то написанный Visual Studio или разработчиком – помещается в один файл исходного кода. Хотя проектировщик Windows Forms Visual Studio стремится писать код только в одном разделе этого файла, можно размещать код разработчика и сгенерированный код в одних и тех же разделах, при наличии вероятности, что проектировщик Windows Forms перепишет код, написанный разработчиком.

15.2 Частичные классы и принципы проектирования Windows Forms для событий

Когда Visual Studio 2005 создает для вас реализацию обработки события, код обработчика события/регистрации записывается в файл FormName.Designer.cs, причем только заглушка метода обработки события автоматически записывается в файл FormName.cs. Цель этой схемы в том, чтобы проектировщик Windows Forms писал весь связанный с событием код, который может быть автоматизирован (подключение метода обработки события к обработчику события и т.д.). Проектировщик не может создавать только специфическую логику программы, которая должна выполняться внутри метода обработки события. Когда Visual Studio заканчивает делать для вас все, что может, вы получаете (1) весь связанный с событием подключающий код, помещенный в файл FormName.Designer.cs; с (2) заглушкой метода обработки события, помещенной в файл FormName.cs. Вам остается только закончить реализацию обработки события, написав требуемый код в заглушке метода обработки события.

15.3 Пошаговый разбор – обработка события Windows Forms

Следующие шаги пошагово разбирают реализацию метода обработки события FormClosing в форме Windows с именем MainForm.
1.    С использованием Visual Studio .NET создайте новый проект Windows Forms и добавьте новую форму с именем MainForm.
2.    Открыв MainForm в режиме конструктора, щелкните правой кнопкой мыши по открытому участку формы (не по элементу управления), и выберите «Свойства» из всплывающего меню. Появится диалоговое окно «Свойства», отображающее свойства формы или события. Если это еще не выбрано, нажмите кнопку «События» (она имеет иконку светящейся молнии) на панели инструментов вверху диалогового окна свойства.
3.    В диалоговом окне события найдите событие, на которое ваше приложение должно реагировать. В нашем случае это событие FormClosing. Дважды щелкните где-нибудь в строке, в которой указано FormClosing.

В этот момент происходят две вещи.

Первое – конструктор  Windows Forms вставляет следующую строку в файл MainForm.Designer.cs.

this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(
    this.MainForm_FormClosing);

Второе – конструктор   Windows Forms вставляет следующую заглушку метода в файл MainForm.cs.
private void MainForm_FormClosing(object sender,

    FormClosingEventArgs e)
{
 // ваш код обработки события идет здесь
}

* При использовании .NET 1.x (не имеющей частичных классов), генерируется такой же код, но он помещается в один файл MainForm.cs.

Как видно, от вас ничего не скрывают. Весь код, требуемый для реализации логики обработки события, показывается вам и доступен вам для анализа и вероятных изменений при необходимости. Конструктор Windows Forms designer пишет стандартный код, соответствующий рекомендуемым стандартам событий, и помещает этот код в файлы частичного класса, в которых вы затем можете расширять код для связанных с вашим приложением целей.

Если вы хотите изменить имя метода обработки события, сгенерированного для вас конструктором Windows Forms, вы можете сделать это. Обязательно измените имя метода в файле MainForm.cs, и в том месте, где он регистрируется в обработчике события в MainForm.Designer.cs.

Событие FormClosing — это «предшествующее событие», являющееся отменяемым. Это означает, что событие возбуждается перед закрытием формы, и процедура обработки события может отменить событие, тем самым не дав закрыть форму.

В частности, отменяемым это событие делает параметр FormClosingEventArgs, имеющий тип класса, расширяющего System.ComponentModel.CancelEventArgs. Чтобы отменить событие FormClosing, установите булево свойство Cancel FormClosingEventArgs в true так:

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
   e.Cancel = true; // предотвращает закрытие формы
}

15.4 Формы Windows и принципы поточной обработки

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

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

Следовательно, вы можете столкнуться с проблемами поточной обработки, если ваш код использует FileSystemWatcher, и любые из связанных с ним методов обработки события в конечном счете могут запустить обновление элемента управления пользовательского интерфейса. Любые используемые вами сторонние компоненты могут порождать дополнительные фоновые потоки, о которых вы изначально не знаете.

Есть несколько способов уменьшить эти проблемы поточной обработки:
•    Установите свойство SynchronizingObject (при наличии и в соответствующих случаях)
•    Используйте Control.InvokeRequired и Control.Invoke() для вызова кода, обновляющего пользовательский интерфейс.
•    Разработчики компонентов могут использовать классы SynchronizationContext, AsyncOperation, и AsyncOperationManager.

SynchronizingObject (синхронизирующий объект)

Некоторые компоненты .NET предоставляют свойство SynchronizingObject. Примеры этих компонентов включают классы FileSystemWatcher, Timer и Process. Установка SynchronizingObject позволяет вызывать методы обработки события в том же потоке, который создал компонент пользовательского интерфейса, подлежащий обновлению. Например, событие Elapsed(прошло) таймера возбуждается из потока пула потоков. Когда SynchronizingObject компонент таймера  установлен на компонент пользовательского интерфейса, метод обработки события для события Elapsed вызывается в том же потоке, в котором выполняется компонент пользовательского интерфейса. Затем компонент пользовательского интерфейса может быть обновлен из метода обработки события Elapsed.

Нужно отметить, что Visual Studio может автоматически устанавливать свойство SynchronizingObject на элемент управления, содержащий компонент. Следовательно, вы можете вообще не столкнуться с необходимостью явно устанавливать свойство SynchronizingObject.

Однако существуют сценарии, в которых может понадобиться явно установить свойство SynchronizingObject. Например, когда вы имеете библиотеку классов, экземпляр которой создается внутри Windows Form, и эта библиотека классов содержит экземпляр FileSystemWatcher. FileSystemWatcher порождает дополнительный фоновый поток, из которого возбуждаются его события. затем эти события обрабатываются внутри библиотеки классов. Пока все хорошо. Библиотека классов может обрабатывать события, так как у нее отсутствует привязка к потоку, свойственная элементам управления Windows Forms. Библиотека классов может, в ответ на получение события FileSystemWatcher, возбудить новое событие, которое затем обрабатывается в экземпляре, содержащем Windows Form. Возникнет следующее исключение, если SynchronizingObject не был установлен на эту форму (или на соответствующий элемент управления на ней), или код, обновляющий пользовательский интерфейс, не был вызван через Control.Invoke(), как описано далее.

System.InvalidOperationException не было обработано:
Неправильная межпоточная операция: Элемент управления 'ControlNameHere' был вызван из потока, отличного от потока, в котором он был создан.

Control.Invoke() и InvokeRequired

Есть два важных исключения из правила, гласящего, что Элементы управления Windows Forms не могут вызываться из потока, отличного от потока, в котором они были созданы. Все элементы управления наследуют метод Invoke() и свойство InvokeRequired, которые могут быть вызваны из других потоков. Invoke()принимает единственный аргумент, имеющий тип делегата. При вызове Invoke() заставляет делегат вызвать все методы, зарегистрированные в нем. Любой код, вызванный через Invoke(), будет выполнен в том же потоке, в котором находится элемент управления. Чтобы обновить элементы управления пользовательского интерфейса, выполняющиеся в одном потоке, из кода в другом потоке, просто (1) выделите код, обновляющий элемент управления пользовательского интерфейса, в отдельный метод; затем (2) зарегистрируйте этот метод в делегате, который затем (3) передайте в метод Invoke() элемента управления пользовательского интерфейса.

InvokeRequired возвращает истину, когда текущий код выполняется в потоке, отличном от потока, в котором был создан элемент управления. Вы можете запросить значение InvokeRequired, чтобы определить, может ли ваш код напрямую обновить элемент управления, или такие обновления должны передаваться через метод Invoke().

SynchronizationContext, AsyncOperation и AsyncOperationManager

Впервые появившиеся в версии 2.0 среды разработки .NET, эти классы предоставляют разработчикам компонентов, возбуждающим события асинхронно, еще одну возможность решить проблемы поточной обработки, описанные выше. Основное преимущество использования System.ComponentModel.AsyncOperation в том, что он обеспечивает решение проблем поточной обработки (описанных выше) в публикаторе события (компоненте), тогда как две представленных выше альтернативы (Control.Invoke и SynchronizingObject) дают решение для подписчиков.

16. Отменяемые события

Отменяемые события обычно возбуждаются компонентом, собирающимся выполнить некое действие, которое может быть отменено, или совершение которого может быть запрещено. Событие FormClosing класса Windows Form – пример отменяемого события. Типичный сценарий, в котором вам нужно запретить закрытие формы, происходит, когда пользователь не сохранил изменения. В этом сценарии ваш метод обработки события FormClosing может реализовать логику, обнаруживающую наличие несохраненных изменений. Если таковые имеются, то логика может попросить пользователя сохранить свои изменения. Если пользователь выберет сохранить свои изменения, ваша логика отменит событие FormClosing. Это предотвратит закрытие формы, тем самым дав пользователю возможность пересмотреть свои изменения и, вероятно, сохранить их перед повторной попыткой закрыть форму.

Внутренние механизмы отменяемого события могут быть весьма простыми. Учитывая, что события часто сообщают подписчикам, что изменение в состоянии или какое-то другое действие вскоре произойдет, это «предсобытие» дает публикатору события отличную возможность определить, должен ли публикатор позволять изменению в состоянии (или действию) совершиться. Если действию разрешено совершиться (т.е. ничто не говорит публикатору прервать операцию), то публикатор позволяет совершиться изменению в состоянии и впоследствии/дополнительно возбуждает постсобытие.
Итак, отменяемое событие – на самом деле два события и некоторое действие, совершающееся между этими событиями. «Предсобытие» возникает перед действием. После этого действие совершается (или нет). Если действие совершается, обычно возбуждается «постсобытие». Если быть точным, никакое событие не отменяется, несмотря на то, что мы говорим, что имеем отменяемое событие. Наоборот, отменяется действие, совершающееся между двумя событиями, — и, скорее всего, запуск этого действия вообще запрещается.

В поддержку вышеуказанного понятия отменяемого события среда разработки .NET предоставляет класс System.ComponentModel.CancelEventArgs, который можно использовать непосредственно или расширять для связанных с приложением целей. CancelEventArgs расширяет System.EventArgs путем предоставления булева свойства Cancel, которое, если установлено в true подписчиком события, используется публикатором события для отмены события. Код публикатора события создает экземпляр CancelEventArgs, который отправляется подписчикам, когда возбуждается предсобытие. По умолчанию, методы обработки события (в любых/всех подписчиках) запускаются одновременно. Следовательно, изменение состояния (или действие), о котором сообщает предсобытие, может совершиться только после завершения выполнения всех запущенных методов обработки события. Разумеется, публикатор события хранит свою ссылку на экземпляр CancelEventArgs после возбуждения события. Поэтому, если любые методы обработки события установят свойство Cancel в true, публикатор события увидит это до того, как попытается приступить к изменению состояния, и сможет отреагировать соответственно.

Последовательность действий может быть примерно такой:
1.    Публикатор события создает экземпляр System.ComponentModel.CancelEventArgs (или его подкласса) с именем ‘e’
2.    Затем метод возбуждения события возбуждает событие, передавая ‘e’ подписчикам события (возвращая значение Cancel в false)
3.    Затем метод обработки события (в подписчике события) устанавливает значение e.Cancel в true, вероятно, спрашивая у пользователя
4.    Затем метод возбуждения события получает значение e.Cancel и реагирует соответственно. В случае если e.Cancel = true, логика не даст совершиться изменению состояния или действию (например, закрытие формы).

В случае если событие имеет несколько подписчиков, событие будет отменено, если любой из методов обработки события установит e.Cancel = true. Точнее, публикатор события увидит, что e.Cancel = true, когда последний метод обработки события возвратит значение (они вызываются одновременно).

В конечном счёте, CancelEventArgs предоставляет подписчику события механизм передачи значения true | false публикатора события. Фактическая работа и смысл «отмены события» —  полностью на ваше усмотрение, так как вы должны писать логику, реагирующую на значение e.Cancel.

Отмена долго выполняющейся операции

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

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

Относительно простой и верный способ начать асинхронную обработку – ознакомиться с компонентом System.ComponentModel.BackgroundWorker. Компонент BackgroundWorker позволяет вам запускать задачу асинхронно, сообщать о прогрессе задачи (процент выполнения), отменять задачу после ее запуска, и сообщать о завершении задачи (с помощью возврата значения). Дальнейшее описание моделей асинхронной обработки и вариантов многопоточности и связанных с ними проблем выходит за пределы данной статьи.

17. События веб-форм ASP.NET

Нет ничего сугубо уникального в концепциях, задействованных в создании событий, обработчиков событий, и методов обработки событий в веб-приложениях ASP.NET. Все, что сказано в этой статье о создании пользовательских событий и обработчиков событий, с таким же успехом применяется к веб-приложениям ASP.NET, как и к приложениям Windows Forms и библиотекам кода C#. Веб-приложения ASP.NET радикально отличаются контекстом, в котором события определяются, возбуждаются и обрабатываются. Отсутствие состояний в HTTP и его модель запрос/ответ, роль конвейера запроса HTTP ASP.NET, роль ViewState(состояние просмотра) и т.д. —  все вступают в действие – и с осложнениями для возбуждения и обработки событий. За пределами основ событий, изложенных в данной статье, находятся специфичные для ASP.NET и связанные с событиями концепции, такие как обратная передача клиентских событий (написанных на ECMA Script, VBScript или JavaScript) и всплывание события.

Эта статья не берется за рассмотрение событий применительно к веб-приложениям ASP.NET, так как нормальное изложение более чем удвоило бы длину статьи (а эта статья уже достаточно длинная!). Но нужно отметить, что изложенные в данной статье основы дадут начинающему разработчику веб-приложений крепкую базу для развития.

В Заметке о консольных и оконных (Windows Forms) приложениях мы отметили существенную разницу между ними. Консольное приложение реализует концепцию императивного (процедурного) программирования, а управление Windows-приложением основано на понятии события (event). События могут создаваться как пользователем, так и возникать в процессе выполнения приложения. Начнем с простых вещей.

Создадим оконное приложение и запустим его на выполнение. С пустой формой мы можем выполнить только несколько стандартных действий: изменить размер, свернуть, свернуть в окно/развернуть и закрыть приложение.

Для изменения размеров формы подведем указатель мыши (1 событие) к любой ее границе (указатель изменит свою форму), перетянем ее в нужном направлении (2 событие) и отпустим кнопку (3 событие). Последние три действия с формой выполняются после клика мышью (событие 4) на кнопках формы.

Ясно, что такое приложение нам не слишком интересно, тем не менее, очевидна связь между событиями и действиями.

Перенесем с Панели элементов на форму объект «Кнопка» (по умолчанию – button1 класса Button). На вкладке «Конструктор» кнопка видна, на вкладке «Код» о ней нет никакой информации. Однако раскрыв файл Form1.Designer.cs, мы увидим в описании класса Form1 поле:

   private System.Windows.Forms.Button button1;

которое задает этот объект, а в методе private void InitializeComponent() обнаружим описание его свойств (имя, местоположение, размер, надпись и т.п.).

Запустим программу снова на выполнение. Нажатие на кнопку (событие)  не влечет за собой никаких действий (кроме того, что между нажатием и отпусканием кнопки она подсвечивается).

Смотрим книгу «для чайников». В ней написано: чтобы связать это событие с каким-либо действием необходимо всего лишь выполнить двойной клик на кнопке, в окне  кода появится заготовка для метода – обработчика события Click:

private void button1_Click(object sender, EventArgs e)
{

}

Увеличим ширину кнопки примерно в три раза. Вставим в тело метода между фигурными скобками оператор:
    button1.Text = DateTime.Now.ToString();
Теперь при нажатии кнопки непосредственно на ней мы можем прочитать текущие дату и время нажатия на кнопку.

«Выдающийся» результат! Есть событие, есть реакция на него (обработка события). Как Вам такая автоматизация программирования!

Заметим, что в панели Свойства для объекта button1 на закладке События (щелчок на «желтой молнии») напротив события Click появился метод button1_Click. В окне кода добавили всего один метод с одним оператором в его теле. Что же еще изменилось? Посмотрим содержимое файла  Form1.Designer.cs. В нем добавилась загадочная строка:

this.button1.Click += new System.EventHandler(this.button1_Click);

Расшифруем ее. Ключевое слово this – это ссылка на текущий объект Form1 (забавно, что имя объекта совпадает с именем класса). Объект button1 размещен на форме Form1. А Click – очевидно это событие, клик на кнопке.  EventHandlerделегат (delegate), представляет метод, который будет обрабатывать событие, не имеющее данных (объявлен в библиотеке System). Тип события обязательно должен совпадать с типом делегата. В скобках указывается имя этого метода button1_Click.
Переведем смысл оператора на русский язык:
Объект.Событие += new Делегат(Метод_обработки);
Символ + определяет подписку обработчика события.
Очевидный вывод: Подписка на событие с использованием делегата приводит к вызову метода при возникновении события.

Возможен ли разрыв связи между событием и методом его обработки? И нет ли у вас ощущения статичности таких связей? Можно ли то же самое достичь программным путем?

Реализуем второй вариант действий:
1) поместим кнопку button1 на форме Form1;
2) в конструктор формы добавим один оператор, тогда:
public Form1()
{
InitializeComponent();
button1.Click += new System.EventHandler(button1_Click);
}
3) в описание класса добавим метод:
private void button1_Click(object sender, EventArgs e)
{
button1.Text = DateTime.Now.ToString();
}
4) запустим программу на выполнение, сравним результаты;
5) появился ли оператор подключения в файле FormDesigner.cs ?

Заметим, что этот файл Form1.Designer.cs является текстовым описанием формы и размещенных на ней элементов после запуска программы, что позволяет отобразить ее в режиме конструктора.

Далее многое можно изменять программным путем.

Итак, событие – это сообщение другим объектам программы, что произошло какое-то действие. Действие может быть инициировано пользователем (нажатие клавиши) или же в результате выполнения какого-то фрагмента программы (по условию).

Объект, который вызывает событие, называется отправителем (sender) сообщения, а объект, который сообщение получает – получателем. Роль «почтальона» выполняет делегат. Получатель сообщения имеет метод, который автоматически выполняется в ответ на исходное событие. В нашем примере отправителем и получателем сообщения является объект button1 («makes himself»).

Платформа .NET Framework поддерживает простое программирование событий, из-за чего начинающие программисты часто не вникают в работу событий.

Событием в языке C# называется сущность, предоставляющая две возможности: сообщать об изменениях, а для его пользователей — реагировать на них. В объявлениях классов визуальных компонентов мы найдем большое количество событий, которые могут быть вам полезны. Подсчитайте, сколько событий связано с формой? У меня получилось – 76. А для кнопки – 58, не мало? Если же вам необходимо создать собственное событие, то вы можете его просто объявить:

public event EventHandler myEvent;

Рассмотрим, из чего состоит объявление. Сначала идут модификаторы события, затем ключевое слово event, после него — тип события, который обязательно должен быть типом-делегатом, и идентификатор события, то есть его имя myEvent. Ключевое слово event сообщает компилятору о том, что это не публичное поле, а специальным образом раскрывающаяся конструкция, скрывающая от программиста детали реализации механизма событий (пока это замечание пропустите).

В C# разрешается формировать какие угодно разновидности событий. Но ради совместимости программных компонентов со средой .NET Framework следует придерживаться рекомендаций, которые по существу, сводятся к следующему требованию: у обработчиков событий должны быть два параметра. Первый из них — ссылка на объект, формирующий событие, второй — параметр типа EventArgs, содержащий любую дополнительную информацию о событии, которая требуется обработчику. То есть:

void обработчик(object отправитель, EventArgs е) {//…}

Как правило, отправитель — это параметр, передаваемый вызывающим кодом с помощью ключевого слова this. Параметр е типа EventArgs содержит дополнительную информацию о событии и может быть проигнорирован, если он не нужен.
Отметим, что и в первом примере с кнопкой автоматически сгенерировался заголовок метода, обеспечивающего обработку клика мышкой:
private void button1_Click(object sender, EventArgs e)
Сам класс EventArgs не содержит полей, которые могут быть использованы для передачи дополнительных данных обработчику, он служит в качестве базового класса, от которого получается производный класс, содержащий все необходимые поля. Тем не менее, в классе EventArgs имеется одно поле Empty типа static, которое представляет собой объект типа EventArgs без данных.
В среде .NET Framework предоставляется встроенный обобщенный делегат под названием EventHandler<TEventArgs>. В данном случае тип TEventArgs обозначает тип аргумента, передаваемого параметру EventArgs события.
Для обработки многих событий параметр типа EventArgs оказывается ненужным. Поэтому с целью упрощения создания кода в подобных ситуациях в среду .NET Framework и был внедрен необобщенный делегат типа EventHandler, используемый для объявления обработчиков событий, которым не требуется дополнительная информация о событиях (см. наш первый пример).

Пример использования обобщенного делегата EventHandler<TEventArgs>

Обобщенный делегат  EventHandler<MyEA> используется для
объявления события Ez:

public event EventHandler<MyEA> Ez;

Аргументы, передаваемые в метод, задаются в классе MyEA, который наследуется от класса  EventArgs.

Постановка задачи «Управление размерами и цветом формы»

Набор цветов: Red, Green, Blue, Yellow + исходный (добавляйте любые!)
Размеры: 500х150, 550×200, 600×250, 650×300

Элементы управления:
Кнопка button1 — Разрешение/Запрет изменение свойств формы
Кнопка button2 — Перекраска формы в желтый цвет без ограничений
Элемент comboBox1 — для выбора цвета: Red, Green, Blue, прежний
Метка label1 — подсказка: «Выберите цвет закраски формы» к comboBox1.

Начальная форма может выглядеть так:

Создаются два класса:
1) Класс Моих Событий Аргументы:

class MyEA : EventArgs // с полями (добавляйте любые) :
{
   public char ch; // буква цвета
   public int htw; // высота формы
}

2) Мой класс Обработка события:

class MyEH
{
   public event EventHandler<MyEA> Ez; // мое событие
   public void OnEz(MyEA c)            // и его метод
}

Далее приводится текст файла Form1.cs с комментариями:

using System;
using System.Drawing;
using System.Windows.Forms;
namespace ОбобщенныйДелегатЦвет
{
public partial class Form1 : Form
{
   public static bool flag = false; // Запретить/разрешить смену цвета 
   char []symb = {'R','G','B','X'}; // массив символов, см.comboBox1 
   int[] heigth = { 150, 200, 250, 300 };
public Form1()
{
   InitializeComponent();
}
// Переключатель флага: Разрешить/Запретить смену цвета формы
private void button1_Click(object sender, EventArgs e)
{
   if (flag)
   {
      flag = false;
      button1.Text = "Изменение цвета формы разрешить!";
   }
   else
   {
      flag = true;
      button1.Text = "Изменение цвета формы запретить!";
   }
}
// Изменение цвета (4 цвета) и размеров формы
private void ChangeBackColor(object sender, MyEA e)
{
   switch (e.ch)
   {
      case 'R':
      {
         this.BackColor = Color.Red;
         this.Height = heigth[0];
         this.Width = 350 + heigth[0];
         break;
      }
      case 'G':
      {
         this.BackColor = Color.Green;
         this.Height = heigth[1];
         this.Width = 350 + heigth[1];
         break;
      }
      case 'B':
      {
         this.BackColor = Color.Blue;
         this.Height = heigth[2];
         this.Width = 350 + heigth[2];
         break;
      }
      case 'Y':
      {
         this.BackColor = Color.Yellow;
         this.Height = heigth[3];
         this.Width = 350 + heigth[3];
         break;
     }
     default: // оставить без изменений
        break;
   }; // end switch
}
// Реакция на изменение выбора цвета формы
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
   MyEH met = new MyEH(); // объект класса Моя обработка событий
   // Получить аргументы: букву цвета и высоту формы - в объект e1:
   int i = comboBox1.SelectedIndex;// номер цвета в массиве symb[]
   MyEA e1 = new MyEA(); // объект класса Мои Аргументы Событий
   e1.ch = symb[i]; // буква цвета
   e1.htw = heigth[i]; // высота формы
   if (flag)
      met.Ez += ChangeBackColor; // Событие Ez связать с методом
   else
      met.Ez -= ChangeBackColor; // Или разорвать связь
   // вызов метода обработки события, связанного с met.Ez
   met.OnEz(e1);
}
// Покраска в желтый без условий
private void button2_Click(object sender, EventArgs e)
{
   MyEH met2 = new MyEH(); // новый объект-событие и пр.
   MyEA e2 = new MyEA(); // новый объект-аргументы:
   e2.ch = 'Y'; // первый
   e2.htw = heigth[3]; // второй
   met2.Ez += ChangeBackColor; // связывание события с методом 
                               // (его аргументы класса MyEA)
   met2.OnEz(e2); // вызов метода
}
} // end класса Form1
// Класс Моих Событий Аргументы
class MyEA : EventArgs
{
   public char ch; // буква цвета
   public int htw; // высота формы
}
// Мой класс Обработка события
class MyEH
{
   public event EventHandler<MyEA> Ez; // мое событие
   public void OnEz(MyEA c) // и его метод
   {
   if (Ez != null) // Есть ли событие?
      Ez(this, c); // Старт события
   } 
} // end класса
} // end namespace!

Вид формы после перекраски:

Примеры

Более эффективное применение этого похода изложено в примере студента Александра  «Компьютерный тренажер «Управление техническим объектом в реальном времени». Сценарный подход«.

Другой пример применения делегатов рассмотрен в посте «Делегаты и методы».


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


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

На примере решения задачи определения площади поверхности шара, подробно описывается как программировать событие в среде Microsoft Visual Studio — C#.


Содержание

  • Условие задачи
  • Выполнение
    • 1. Запустить MS Visual Studio. Создать проект по шаблону Windows Forms Application
    • 2. Размещение элементов управления на форме.
    • 3. Настройка элементов управления типа Label.
    • 4. Элемент управления Button.
    • 5. Корректировка вида формы.
    • 6. Программирование события клика на кнопке «Вычислить«.
      • 6.1. Вызов программного кода.
      • 6.2. Ввод программного кода обработки события.
      • 6.3. Корректировка программного кода.
    • 7. Запуск программы на выполнение.
  • Связанные темы

Поиск на других ресурсах:

Условие задачи

Составить программу, которая по введенному радиусу R находит площадь поверхности шара. Программу реализовать как Windows Forms Application.

Площадь поверхности шара вычисляется по формуле:

02_02_00_005_00_

где R – радиус шара, πконстанта равная 3.1415.

В программе используются следующие элементы управления:

  • Label – метка для вывода сообщений;
  • Button – кнопка для выполнения расчета;
  • TextBox – поле ввода, предназначенное для ввода значения R.

 


Выполнение

1. Запустить MS Visual Studio. Создать проект по шаблону Windows Forms Application

Подробный пример создания нового приложения типа Windows Forms Application описан здесь. Сохранить проект под любым именем.

 

2. Размещение элементов управления на форме.

Из вкладки «Common Controls» выносим на форму четыре элемента управления (рис. 1):

  • два элемента управления типа Label (метка);
  • элемент управления типа Button (кнопка);
  • элемент управления типа TextBox (строка ввода).

C# Windows Forms эементы управления Label Button TextBox

Рис. 1. Элементы управления Label, Button, TextBox

Автоматически создаются четыре объекта с именами label1, label2, button1 и textBox1. По этим именам можно будет иметь доступ к свойствам этих объектов.

Форма приложения будет иметь вид, как показано на рис. 2.

C# Windows Forms форма приложение рисунок

Рис. 2. Форма приложения после размещения label1, label2, button1 и textBox1

 

3. Настройка элементов управления типа Label.

Выделяем элемент управления (объект) label1. В палитре Toolbox изменяем свойство Text, набираем «R = «.

Точно так же изменяется свойство Text для элемента управления label2 (рис. 3). Вводим текст «Площадь поверхности шара = «.

C# Windows Forms свойство Text

Рис. 3. Изменение свойства Text в label1

 

4. Элемент управления Button.

Аналогично к label1 выделяем элемент управления (объект) button1. В свойстве Text вводим строку «Вычислить«.



 

5. Корректировка вида формы.

Изменяем название формы. Для этого выделяем форму. В свойстве Text формы вводим текст «Площадь поверхности шара«.

После корректировки форма будет иметь вид, как показано на рисунке 4.

C# Windows Forms Application форма

Рис. 4. Вид формы после корректировки

 

6. Программирование события клика на кнопке «Вычислить«.
6.1. Вызов программного кода.

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

После нажатия на кнопке «Вычислить» формируется фрагмент кода, который будет обрабатываться нашим приложением. Во время обработки сначала определяется значение введенного радиуса R, затем делается расчет по формуле и вывод результата.

Чтобы вызвать фрагмент кода обработки события на кнопке button1 нужно выполнить такие действия:

  • выделить кнопку button1 (рис. 5 — 1);
  • перейти к вкладке Events (события) в окне свойств (рис. 5 — 2);
  • сделать двойной щелчок «мышкой» напротив события «Click» (рис. 5 — 3).

C# Windows Forms Application событие Click

Рис. 5. Последовательность вызова фрагмента кода обработки события Click

В итоге, откроется вкладка программного кода, который размещен в файле «Form1.cs» (рис. 6).

C# Windows Forms Application обработка событие клик кнопка

Рис. 6. Метод обработки события клика на кнопке button1

Листинг программного кода следующий:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
   public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }

       private void button1_Click(object sender, EventArgs e)
       {

       }
   }
}

 

6.2. Ввод программного кода обработки события.

В методе button1_Click вписываем код обработки события. Листинг метода следующий:

...

private void button1_Click(object sender, EventArgs e)
{
    const double Pi = 3.1415;
    double R,S;
    R = Double.Parse(textBox1.Text);
    S = 4 * Pi * R * R;
    label2.Text = "Площадь поверхности шара = " + S.ToString();
}

...

В коде описываются две переменные R и S типа double. Также описывается константа Pi.

Для преобразования из текстового типа string в тип double используется метод Parse. Таким образом заполняется значение переменной R.

R = Double.Parse(textBox1.Text.ToString());

Подобным образом можно преобразовывать данные и других типов. Например, для типа int можно написать:

int d;
d = Int32.Parse("100"); // d = 100

Результат вычисления площади поверхности шара выводится в label2.Text. Преобразование в тип string осуществляется с помощью метода ToString().

 

6.3. Корректировка программного кода.

В коде, описанном в пункте 6.2 нету защиты от некорректного ввода значения R. Поэтому метод button1_Click нужно переписать следующим образом:

...
private void button1_Click(object sender, EventArgs e)
{
    try
    {
        const double Pi = 3.1415;
        double R, S;
        R = Double.Parse(textBox1.Text);
        S = 4 * Pi * R * R;
        label2.Text = "Площадь поверхности шара = " + S.ToString();
    }
    catch (FormatException ex)
    {
        label2.Text = "Ошибка - " + ex.Message;
    }
}
...

Блок

try
{
  ...
}
catch (...)
{
  ...
}

позволяет осуществить программный перехват критической ситуации, которая может возникнуть в результате ввода некорректного значения в поле textBox1 (например «абракадабра»).

В этом случае в свойстве ex.Message буде выведено сообщение:

Ошибка – Input string was not in a correct format.

 

7. Запуск программы на выполнение.

После этого можно запустить нашу программу на выполнение и протестировать ее работу при любых значениях R.

 


Связанные темы

  • Программирование события в Delphi 2010.
  • Пример программирования события в C++ Builder.
  • Пример создания и вызова диалогового окна в MS Visual Studio — C++.

 


Понравилась статья? Поделить с друзьями:
  • Образ windows 10 для ноутбука dell
  • Обработка команд windows 10 в автозагрузке что это
  • Образ windows 10 для восстановления системы х64 скачать
  • Обоснование покупки windows для нужд госучреждения
  • Образ windows 10 для виртуальной машины скачать торрент