|
При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан. Затем: Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз. |
Введение в windows-формы
Делегаты
Когда вы изучали синтаксис языка C#, то проходили понятие делегатов и событий. Изучение синтаксиса обычно проходит в консольных приложениях, где смысл использования делегатов и событий зачастую остается неясным. Между тем, это основа всего Windows-программирования. Рассмотрим вначале еще раз, что же это такое, а затем интерпретируем наши представления для создания Windows-форм.
В обычной жизни делегат — это дипломатический представитель, наделяемый особыми полномочиями своей организацией. Руководство организации заранее определяет, какие функции (методы) должен выполнить делегат: например, осуществить ежегодную проверку филиала, какие параметры следует передать (передать пакет документов) и что получить в ответ (получить ежегодную отчетность). Событием, инициализирующим работу делегата, может быть завершение рабочего года. Организация может располагать несколькими филиалами и не иметь представления на этапе планирования, куда отправится данный сотрудник в качестве делегата.
Когда мы располагаем на форме кнопку, мы знаем, что при наступлении события — нажатия на кнопку — что-то должно произойти: кнопка должна сообщить объекту или объектам, что мы нажали на нее. Однако, эти объекты еще могут быть не определены. Вместо того чтобы привязывать кнопку к конкретному объекту, мы связываем событие кнопки с делегатом, а когда приложение будет выполняться, назначим делегатом тот метод, который будет необходим.
Запустите Visual Studio .NET. Создайте новое консольное приложение и назовите его Delegate. В классе Class1 объявляем делегат:
class Class1
{
delegate void Mydelegate (string s);
//…продолжение кода.
}Синтаксис объявления делегата такой: сначала пишем ключевое слово delegate, затем — тип возвращаемого значения ( void в нашем примере), потом — произвольное имя делегата (у нас это Mydelegate ), после которого в круглых скобках перечисляем параметры (у нас только один параметр типа string ). Объявленный делегат появится в окне Class View (со специальным значком для делегатов) (рис. 1.30).
В этом же классе добавим метод, который просто-напросто будет выводить некоторую переменную s на экран:
class Class1
{
delegate void Mydelegate( string s);
static void Metod2В большинстве учебников по программированию, даже написанных на русском языке, принято давать названия объектов на английском языке. В результате достигается железная строгость изложения и путаница у новичков, которые тратят дополнительные усилия на разбор названий, предопределенных средой слов, и поиском их перевода в Lingvo. Конечно, в коммерческих распределенных проектах следует придерживаться общих правил, но для большей ясности далее в некоторых местах я буду писать "Metod" а не "Method", "Chelovek" а не "Man". ( string s)
{
Console.WriteLine(s);
}
//…продолжение кода.
}Когда мы создаем класс, то вначале мы его объявляем, а затем создаем объект класса (или его экземпляр). Мы объявили делегат Mydelegate, а теперь создадим экземпляр этого делегата del:
[STAThread]
static void Main(string[] args)
{
Mydelegate del = new Mydelegate(Metod);
//…продолжение кода.
}Делегат Mydelegate связывается здесь с методом Metod. Теперь созданному экземпляру делегата передадим в качестве параметра переменную типа string, заключенную в кавычки:
[STAThread]
static void Main(string[] args)
{
Mydelegate del = new Mydelegate(Metod);
del("переменная типа string, которую принимает Metod, вызываемый делегатом del");
}Запустите приложение (Ctrl+F5 — для консольных приложений — чтобы иметь возможность его разглядеть) (рис. 1.31).
Как это работает? Экземпляру делегата del мы передаем переменную типа string, заключенную в скобках. Экземпляр del принадлежит делегату Mydelegate, который принимает метод Metod. Этот метод, в свою очередь, принимает переменную string s, которая выводится затем на экран. Обратите внимание, что сигнатуры делегата Mydelegate и метода Metod одинаковы! Если мы изменим тип принимаемой методом переменной на, например, int, среда выдаст ошибку.
using System;
namespace Delegate
{
class Class1
{
delegate void Mydelegate( string s);
static void Metod( string s)
{
Console.WriteLine(s);
}
[STAThread]
static void Main(string[] args)
{
Mydelegate del = new Mydelegate(Metod);
del("переменная типа string, которую принимает Metod, вызываемый делегатом del");
}
}
}
Листинг
1.1.
Полный листинг проекта Delegate
Создайте новое консольное приложение. Назовите его Delegate2. Поскольку этот пример очень похож на предыдущий, просто приведу полный листинг с комментариями:
using System;
namespace Delegate2
{
//Создаем новый класс chelovek
class chelovek
{
//Объявляем переменную slovo
public string slovo;
//Создаем метод govorit
public void govorit( string s)
{
Console.WriteLine( slovo + s);
}
class Class1
{
//Объявляем делегат Mydelegate, который имеет ту же саму сигнатуру, что и метод govorit
delegate void Mydelegate(string s);
[STAThread]
static void Main(string[] args)
{
//Создаем экземпляр student класса chelovek
chelovek student = new chelovek();
//Создаем экземпляр del делегата Mydelegate
Mydelegate del = new Mydelegate(student.govorit);
//Переменной slovo экземпляра student присваиваем значение "привет"
student.slovo = "привет";
// Экземпляру делегата del передаем переменную в кавычках
del(" - Сказал студент через делегат");
//Переменной slovo экземпляра student присваиваем значение "пока"
student.slovo = "пока";
// Экземпляру делегата del передаем переменную в кавычках
del(" - Сказал студент через делегат");
}
}
}
}
Листинг
1.2.
В этом примере мы дважды передаем переменную одному экземпляру делегата (рис. 1.32).
Конечно же, здесь тот же самый результат можно было получить без всякого введения делегатов — просто инициализируя переменную slovo. Но пока для нас важно не найти наилучший способ получения заданного результата, а разобраться, как же работают делегаты. Создайте новое консольное приложение и назовите его Matem. Далее опять привожу полный код с комментариями:
using System;
namespace Matem
{
//Создаем новый класс matematika
class matematika
{
//Объявляем переменную a
public int a;
//Создаем метод calculate
public void calculate()
{
int b = a*a;
int c = a*a*a;
int d = a*a*a*a;
Console.WriteLine ("Само число: " + a + "\nКвадрат: " + b + "\nКуб: " + c + " \nЧетвертая степень:" + d);
}
}
class Class1
{
[STAThread]
static void Main(string[] args)
{
//Создаем экземпляр primer класса matematika
matematika primer = new matematika();
//Переменной a экземпляра primer присваиваем значение 2
primer.a = 2;
//Вызываем метод calculate
primer.calculate();
}
}
}
Листинг
1.3.
Результатом выполнения этой программы будет вычисление квадрата, куба и четвертой степени значения переменной (рис. 1.33):
Теперь создадим делегата и его экземпляр (можно создать новое консольное приложение — Matem2 — или изменить существующее):
using System;
namespace Matem2
{
//Создаем новый класс matematika
class matematika
{
//Объявляем переменную a
public int a;
//Создаем метод calculate
public void calculate(int chislo)
{
int b = a*a;
int c = a*a*a;
int d = a*a*a*a;
Console.WriteLine ("Само число: " + a + "\nКвадрат: " + b + "\nКуб: " + c + " \nЧетвертая степень:" + d);
}
}
class Class1
{
delegate void Mydelegate(int chislo);
[STAThread]
static void Main(string[] args)
{
//Создаем экземпляр primer класса matematika
matematika primer = new matematika();
//Создаем экземпляр del делегата Mydelegate
Mydelegate del = new Mydelegate(primer.calculate);
//Переменной a экземпляра primer присваиваем значение 2
primer.a = 2;
// Экземпляру делегата del передаем переменную
del(1);
//Переменной a экземпляра primer присваиваем значение 3
primer.a = 3;
// Экземпляру делегата del передаем переменную
del(2);
//Переменной a экземпляра primer присваиваем значение 4
primer.a = 4;
// Экземпляру делегата del передаем переменную
del(3);
}
}
}
Листинг
1.4.
Результатом выполнения этой программы будет последовательный вывод самого числа, его квадрата, куба и четвертой степени (рис. 1.34):




