Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: Перевызов событий?

всем привет, имеется данный пример:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public delegate void EventDelegate();
 
    public class MyClass
    {
        public event EventDelegate myEvent = null;
 
        public void InvokeEvent()
        {
            myEvent.Invoke();
        }
    }
 
    class Program
    {
        // Методы обработчики события.
 
        static private void Handler1()
        {
            Console.WriteLine("Обработчик события 1");
        }
 
        static private void Handler2()
        {
            Console.WriteLine("Обработчик события 2");
        }
 
        static void Main()
        {
            MyClass instance = new MyClass(); 
 
            // Присоединение обработчиков событий. (Подписка на событие)
            instance.myEvent += new EventDelegate(Handler1);
            instance.myEvent += Handler2;
 
            // Метод который вызывает событие.
            instance.InvokeEvent();
 
            Console.WriteLine(new string('-', 20));
 
            // Открепляем Handler2().
            instance.myEvent -= new EventDelegate(Handler2);
 
            instance.InvokeEvent();
 
            // Delay.
            Console.ReadKey();
        }
    }
Зачем тут метод InvokeEvent, который перевызывает событие myEvent?

Зачем вообще перевызывать событие? Почему не вызвать его "напрямую" - как метод
Ответ:
Сообщение от BadCats
Зачем тут метод InvokeEvent, который перевызывает событие myEvent?
Зачем вообще перевызывать событие? Почему не вызвать его "напрямую" - как метод
Затем, что если вы сделаете наследник от MyClass, то он не сможет вызвать событие myEvent, поскольку событие может вызывать только класс, в котором событие объявлено.
Сделав же метод InvokeEvent (обычно он делается с модификатором protected), вы даете возможность вызвать событие наследникам MyClass.
Вопрос: Поясните мне пример события,которое я сейчас приведу

Как это всё осуществляется? Не полностью понял. Вот код
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Демонстрация использования простейшего события.
using System;
// Объявляем делегат для события.
delegate void MyEventHandler();
// Объявляем класс события.
class MyEvent {
public event MyEventHandler SomeEvent;
// Этот метод вызывается для генерирования события.
public void OnSomeEvent() {
if(SomeEvent != null) SomeEvent();
}
}
class EventDemo {
// Обработчик события.
static void handler() {
Console.WriteLine("произошло событие.");
}
public static void Main() {
MyEvent evt = new MyEvent();
// Добавляем метод handler() в список события.
evt.SomeEvent += new MyEventHandler(handler);
// Генерируем событие.
evt.OnSomeEvent();
}
}
Ответ: Смотрите, у вас есть .Net Framework, который по сути огромный набор различных классов, событий, делегатов, интерфейсов и много чего еще сгруппированных и разложенных по различным библиотекам и пространствам имен. Ваша форма, кнопка, и т.д. - уже готовые описанные классы, которые уже реализованы, в которых уже описанны все доступные и присущие им события. Вы же, пользуясь ими, просто обвязываете их события со своими обработчиками.
Если посмотрите, то при создании любой вашей формы, она наследуется от базового класса Form, что автоматически предоставляет весь функционал (включая события и методы, которые их генерируют, которые в свою очередь уже реализованы и скрыты от вас) класса Form. Далее, если вы посмотрите реализацию метода InitializeComponent() в конструкторе вашей формы вы увидите, что в нем создаются все элементы управления, что вы размещали на форме, присваиваются те или иные значения свойств, и главное, подписываются на события и определяют методы их реализующие. Просто студия все это делает в автоматическом режиме и выносит в файл (имя формы).Designer.cs. Но все это можно делать и вручную самому. Допустим если стоит задача, что по нажатию кнопки вам нужно добавит на форму еще одну кнопку, нажатие на которой создаст еще кнопку и тд. Тогда вы можете в обработчике этой кнопки создать объект класса Button, разместить ее на форме и подвязаться на событие Click, при этом обработчиком может служить этот же самый метод.
Но это то что касается элементов управления. События же могут быть использованы и реализованы много где еще, если того требует задача. Это всего лишь механизм, позволяющий решить ряд задач, возникающих в момент разработки. Вот еще пример. У вас есть класс, который работает в отдельном потоке. Его задача, допустим, какой-то очень длительный расчет или мониторинг чего либо. И вам нужно знать когда он окончит действие, получить результат и тд. Как узнать что он закончил работу? Тут и поможет событие. Все что вам потребуется - это описать событие в классе (пусть ResultReady), по завержению сгенерировать событие ResultReady(), а в вызывающем классе подписаться на него myObj.ResultReady +- OnResultReady; и в этом методе уже производить дальнейшую обработку.
Вопрос: Переопределение virtual события

всем привет, имеется такой пример:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    public delegate void EventDelegate();
 
    interface IInterface
    {
        event EventDelegate MyEvent; // Абстрактное событие.
    }
 
    public class BaseClass : IInterface
    {
        EventDelegate myEvent = null;
 
        public virtual event EventDelegate MyEvent // Виртуальное событие.
        {
            add { myEvent += value; }
            remove { myEvent -= value; }
        }
 
        public void InvokeEvent()
        {
            myEvent.Invoke();
        }
    }
 
    public class DerivedClass : BaseClass
    {
        public override event EventDelegate MyEvent // Переопределенное событие.
        {
            add
            {
                base.MyEvent += value;
                Console.WriteLine("К событию базового класса был прикреплен обработчик - {0}", value.Method.Name);
            }
            remove
            {
                base.MyEvent -= value;
                Console.WriteLine("От события базового класса был откреплен обработчик - {0}", value.Method.Name);
            }
        }
    }
 
    class Program
    {
        // Методы обработчики события.
 
        static private void Handler1()
        {
            Console.WriteLine("Обработчик события 1");
        }
 
        static private void Handler2()
        {
            Console.WriteLine("Обработчик события 2");
        }
 
        static void Main()
        {
            DerivedClass instance = new DerivedClass();
 
            // Присоединение обработчиков событий.
            instance.MyEvent += new EventDelegate(Handler1);
            instance.MyEvent += new EventDelegate(Handler2);
 
            // Метод который вызывает событие.
            instance.InvokeEvent();
 
            Console.WriteLine(new string('-', 20));
 
            // Открепляем Handler2().
            instance.MyEvent -= new EventDelegate(Handler2);
            instance.InvokeEvent();
 
            // Delay.
            Console.ReadKey();
        }
    }
К данному примеру у меня три вопроса:

1)переопределение события с помощью virtual - также как и метод InvokeEvent в данном примере - позволяет классам наследникам вызывать событие путем переопределения?

2)Если у меня одно событие - можно ли подписывать при переопределении это одно событие на разные обработчики переопределяя его в разные классы - т.е я имею ввиду, если я одно виртуальное событие переопределил в три разных класса и в каждом из них подписал на разные обработчики событий, то если я затем создам екземпляр конкретного класса, то у меня сработают только обработчики из него , или из всех трех классов - т.к я переопределил одно событие в эти три класса?

3)также меня интересует эта строка:
Code
1
event EventDelegate MyEvent; // Абстрактное событие.
- как видно из комментария, автор курса говорит, что это абстрактное событие, но как я понимаю, это не тоже самое, что и с ключевым словом abstract ? я имею ввиду, что если по сущности это было бы тоже самое , что и с ключевым словом abstract , то мы обязаны были бы его переопределить, на как видно, что мы этого не делаем. Так, что же подразумевается под понятием "абстрактное событие" ?
Ответ:
Сообщение от Storm23
Не.
Подразумевалось, что событие будет вызываться через все тот же InvokeEvent, а не напрямую наследником.
Надо было, конечно, уточнить.

Сообщение от Storm23
Там наверно "абстрактный" просто обозначает "некий, неопределенный, не несущий конкретного смысла". Безотносительно к термину программирования.
Вот это и напрягает: использование в обучающем материале терминов, имеющих вполне конкретное значение в обучаемом предмете, но при этом вкладывая в эти термины понятия, которые безотносительны к обучаемому предмету.
Вопрос: Как правильно удалять события

Как правильно удалять события в данном случае, ибо каждое добавленное событие сохраняется. Целесообразно ли использовать IDisposable и в нем уже описывать удаление событий из ExecutingEvent? Или же придумать просто отдельный метод который удалял бы добавленные события?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
class Program
    {
        static IDoable doable;
 
        static ExecutingEvent exEvent = new ExecutingEvent();
 
        static void Main(string[] args)
        {
            while (true)//выполняем вечно
            {
                Console.Write("№: ");
                switch (Console.ReadLine())
                {
                    case "1": doable = new ClassA(exEvent); break;
                    case "2": doable = new ClassB(exEvent); break;
                    default: continue;
                }
                doable.Do();
            }
        }
    }
    public delegate void OnSomethingHandler(object sender, EventArgs e);//делегат описывающий сигнатуру события OnSomething
 
    public class ExecutingEvent//класс с событием OnSomething
    {
        public event OnSomethingHandler OnSomething;//событие
 
        public ExecutingEvent() { }
 
        public void CallOnSomething()//вызов события
        {
            OnSomething?.Invoke(this, new EventArgs());//если OnSomthing не null
        }
    }
 
    public interface IDoable { void Do(); }//интерфейс обеспечивающий создание метода Do
 
    public class ClassA : IDoable
    {
        public ExecutingEvent ExampleEE;//экземпляр класса с событием OnSomething
 
        public ClassA(ExecutingEvent exampleEE)
        {
            ExampleEE = exampleEE;//ссылка на внешний ExecutingEvent
            ExampleEE.OnSomething += ExampleClassA_OnSomething;//добавляем новое событие во внешний ExecutingEvent
        }
 
        private void ExampleClassA_OnSomething(object sender, EventArgs e)//добавляемое событие
        {
            Console.WriteLine("Я сделал это в классе А");
        }
 
        public void Do()//метод вызывающий событие OnSomething из ExampleEE
        {
            ExampleEE.CallOnSomething();
        }
    }
 
    public class ClassB : IDoable
    {
        public ExecutingEvent ExampleEE;//экземпляр класса с событием OnSomething
 
        public ClassB(ExecutingEvent exampleEE)
        {
            ExampleEE = exampleEE;//ссылка на внешний ExecutingEvent
            ExampleEE.OnSomething += ExampleEE_OnSomething;//добавляем новое событие во внешний ExecutingEvent
        }
 
        private void ExampleEE_OnSomething(object sender, EventArgs e)//добавляемое событие
        {
            Console.WriteLine("Я сделал это в классе B");
        }
 
        public void Do()//метод вызывающий событие OnSomething из ExampleEE
        {
            ExampleEE.CallOnSomething();
        }
    }
Ответ:
Сообщение от AnEk72
Целесообразно ли использовать IDisposable и в нем уже описывать удаление событий из ExecutingEvent? Или же придумать просто отдельный метод который удалял бы добавленные события?
Без особой разницы. IDisposable немного надежнее в плане того, что вы можете гарантированно его вызвать через using.
Еще вариант - слабые ссылки и отписка в финализаторе.
Вот здесь еще почитайте, там подробно рассмотрены разные варианты
Вопрос: Цикл, обрабатывающий события от нескольких источников

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

Требуется создать цикл обработки событий или сообщений от двух или более источников. Т. е., допустим, имеется несколько (более одного) источника событий, каждый из них порождённые им события помещает в свою очередь, причём эти очереди разные, общей единой очереди событий, в которую все источники делали бы запись, не существует. События могут считываться из очередей любым возможным способом — могут использоваться для этого системные вызовы операционной системы (допустим, read/write в Unix и Linux), мьютексы и блокировки чтения/записи, какие-то специальные библиотечные функции и т. п. Источники событий могут быть любые — пайпы, FIFO, сокеты, X Server, посылающий клиентской программе события клавиатуры и мыши, и т. п. Главное, чтобы их было несколько, при этом они могут быть и однотипными, и совершенно разной природы.

Работать цикл должен так. При поступлении события с любого из источников он должен его считывать, обрабатывать и выполнять какое-то положенное ответное действие. В случае же если событий ни на одном из источников нет (все прежние события уже считаны и обработаны циклом, а новых ещё не поступило), цикл должен блокироваться и останавливаться в ожидании нового события. Как только событие поступило, не важно с какого из источников, цикл должен разблокироваться и обрабатывать его.

В случае одного источника событий задача тривиальна и не вызывает никаких вопросов. А как быть, если их несколько? Какие существуют решения и подходы?
Ответ: Хочу заметить, что реализация с кучей потоков, каждый из которых обрабатывает свой канал и скидывает свой выхлоп в "очередь событий" гораздо мощнее системного select.
Вопрос: Описать класс ИСТОРИЧЕСКОЕ СОБЫТИЕ (поля: ЧИСЛО, МЕСЯЦ, ГОД, СОБЫТИЕ)

Описать класс ИСТОРИЧЕСКОЕ СОБЫТИЕ (поля: ЧИСЛО, МЕСЯЦ, ГОД, СОБЫТИЕ).
Операция класса: вычисление интервала в днях, прошедшего между двумя заданными историческими событиями (-);
Статический метод класса: поиск наиболее позднего события в массиве событий.
Функция демонстрационной программы: поиск в массиве заданного события по его названию.
Ответ: Может немного оффтоп, я тоже начинающий и вот моя версия
программа
Код C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    class Program
    {
        static void Main(string[] args)
        {
            List<HistoricalEvent> events = new List<HistoricalEvent>(); //создание списка событий
            do
            {
                Console.WriteLine("Enter the name of the event :");
                string name = Console.ReadLine();
                Console.WriteLine("Enter the date when the event occurred (yyyy-mm-dd):");
                string date = Console.ReadLine();
                try
                {
                    HistoricalEvent curr_event = new HistoricalEvent(date, name);
                    events.Add(curr_event);                 //заполнение списка до тех пор пока пользователь не отменит
                    Console.WriteLine("Add event?(y/n):");
                }
                catch (FormatException ex)
                {
                    Console.WriteLine("Incorrect date format! Try again.");
                    Console.WriteLine("Repeat?(y/n):");
                }
            } while (string.Compare(Console.ReadLine(), "n") != 0);
 
            Console.WriteLine("Enter the name of the desired event:");
            HistoricalEvent foundEvent =  HistoricalEvent.findByName(events, Console.ReadLine());
            Console.WriteLine("found:");    //поиск события по имени и вывод информации о нем
            if (foundEvent == null)
            {
                Console.WriteLine("Event not found");
            }
            else
            {
                Console.WriteLine(foundEvent.event_name);
                Console.WriteLine(foundEvent.getDate().ToString());
            }
            // Console.ReadLine() //расскоментировать для запуска с отладкой
        }
    }
класс
Код C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
    class HistoricalEvent
    {
        int day;
        int mounth;
        int year;
        public string event_name { get; private set; }
 
        public HistoricalEvent(string event_date, string event_name)
        {
            DateTime date = DateTime.Parse(event_date);
            day = date.Day;                                 //конструктор
            mounth = date.Month;
            year = date.Year;
            this.event_name = event_name;
        }
 
        public DateTime getDate()
        {
            return new DateTime(year, mounth, day);
        }
 
        public int calcInterval(HistoricalEvent finalEvent)
        {
            DateTime startDate = getDate();             //расчет кол-ва дней между текущим событием и заданным
            DateTime endDate = finalEvent.getDate();
 
            return (endDate - startDate).Days;
        }
 
        public static HistoricalEvent findLastEvent(List<HistoricalEvent> events)
        {
            DateTime last_date = events[0].getDate();
            HistoricalEvent last_event = events[0];
            foreach (HistoricalEvent curr_event in events)      //поиск последнего события в списке событий
            {
                if (curr_event.getDate() > last_date)
                {
                    last_date = curr_event.getDate();
                    last_event = curr_event;
                }
            }
            return last_event;
        }
 
        public static HistoricalEvent findByName(List<HistoricalEvent> events, string event_name)
        {
            foreach (HistoricalEvent curr_event in events)      //поиск события по имени
            {
                if (string.Compare(curr_event.event_name, event_name) == 0)
                {
                    return curr_event;
                }
            }
 
            return null;
        }
    }
UPD добавил поиск по имени
Вопрос: Зачем нужны события?

Помогите разобраться, только начал изучать C# и не могу понять пользу от событий. У Шилдта есть пример

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Объявить тип делегата для события. 
delegate void MyEventHandler(); 
// Объявить класс, содержащий событие. 
class MyEvent { 
public event MyEventHandler SomeEvent; 
// Этот метод вызывается для запуска события. 
public void OnSomeEvent() { 
if(SomeEvent != null) 
SomeEvent(); 
} 
} 
class X { 
int id; 
public X(int x) { id = x; } 
// Этот метод экземпляра предназначен в качестве обработчика событий. 
public void Xhandler() { 
Console.WriteLine("Событие получено объектом " + id); 
} 
} 
class EventDemo3 { 
static void Main() { 
MyEvent evt = new MyEvent(); 
X o1 = new X(1); 
X o2 = new X(2); 
X o3 = new X(3); 
evt.SomeEvent += o1.Xhandler; 
evt.SomeEvent += o2.Xhandler; 
evt.SomeEvent += o3.Xhandler; 
// Запустить событие. 
evt.OnSomeEvent(); 
} 
} 
Но ведь можно сделать так
C#
1
2
3
4
5
6
7
8
9
10
11
static void Main() { 
MyEventHandler evt;
X o1 = new X(1); 
X o2 = new X(2); 
X o3 = new X(3); 
evt = o1.Xhandler; 
evt += o2.Xhandler; 
evt += o3.Xhandler; 
evt(); 
} 
} 
По моему так даже проще, не надо создавать обьект класса содержащего события а потом его запускать. Если кто нибудь приведет пример где без них никак, буду благодарен.

Добавлено через 57 минут
И опять почему просто нельзя выполнить метод который реализует событие. К примеру пользователь нажал на кнопку, сразу выполнился метод, а не запускать событие которое выполнит тот же самый метод.
Ответ:
Сообщение от SoftDwarf
правильно события размещать в том же классе для которого они создавались?
Ну естественно, это же события будут именно для этого объекта. Зачем их размещать где-то еще?
Сообщение от SoftDwarf
А методы подписанные на него могут быть в любой части программы.
Абсолютно верно. Создали объект, подписались на его события и ждем уведомлений.
Вопрос: Word - как заставить событие у Application работать всегда?

Помогите решить такую проблему, бьюсь уже далеко не первый день.
Нужно, чтобы при закрытии: 1) документа; 2) оболочки Word срабатывало событие у Application таких процедур как: «Private Sub appWord_DocumentBeforeClose» и «appWord_Quit». Эти события у меня находятся в моем шаблоне, прописанные в созданном классе.
Работа должна происходить следующим образом. В Word есть некий файл, через него я запускаю и подключаю свой шаблон с макросами. На стартовой форме, перед подключением моего шаблона, если юзер выбирает кнопку ОК, шаблон подключается и инициируется событие «Public WithEvents appWord As Word.Application» для процедур: «Private Sub appWord_DocumentBeforeClose» и «Private Sub appWord_Quit».
Моя задача следующая:
1) В процедуре «Private Sub appWord_DocumentBeforeClose» прописана проверка на имя файла, чтобы для определенного документа запускалась специальная форма и в зависимости от выбора юзера этот документ либо закрывается после отработки с пользователем действий, либо закрытие документа приостанавливается, чтобы юзер сам произвел свои манипуляции с документом. Т.е. полученный результат приводит в "Cancel = True".
2) В процедуре «Private Sub appWord_Quit» прописано, чтобы мой шаблон удалялся из списка подключенных шаблонов и надстроек, потому что оболочка Word полностью закрывается.
3) В шаблоне у меня так же имеется моя кнопка, выведенная на моей отдельной вкладке на ленте для закрытия любого активного документа, чтобы не закрывать всю оболочку Word. В моем коде я делаю закрытие документа, если юзер в MsgBox выбирает закрыть документ.
При старте, когда событие Application для процедур: «Private Sub appWord_DocumentBeforeClose» и «Private Sub appWord_Quit» проинициировано, если закрытие документа использовать стандартным способом или же использовать стандартное нажатие в Word сочетание славишь "Ctr+W", событие работает каждый раз независимо от того сколько раз была попытка прервать работу с формой, а затем производить закрытие тем же самым стандартным способом. НО стоит воспользоваться кнопкой с панели, то событие после первого срабатывания перестает срабатывать в дальнейшем, если юзер прерывает работу формы, а затем вторично закрывает документ уже любым перечисленным мной способом.
Я не понимаю почему событие перестает срабатывать в дальнейшем после первого раза???
Т.е. код перестает срабатывать, событие игнорируется, документ просто закрывается, а при закрытии всей оболочки Word шаблон перестает удаляться из списка подключенных:
Кликните здесь для просмотра всего текста

Visual Basic
1
2
3
4
5
6
Public D As New EventClassModule
 
'Для инициирования переменной, чтобы была возможность прервать закрытие документа
Function InitializationEvents()
  Set D.appWord = Word.Application
End Function
Ответ: Если честно, то не понятно практически ничего из того, что вы описываете.

Сообщение от natawka
то при нажатии на форме кнопки, которая должна прерывать выполнение на закрытие документа, происходит цикл и форма перезапускается по новой и так до бесконечности
Ерунда какая-то. Какой у вас происходит цикл?! У вас форма вновь открывается на какое событие? В конструкторе? с чего у вас происходит генерация каких-то событий и действий на создание экземпляра класса?
Вы же не показываете всего кода, а так понять что у вас происходит - очень сложно.

... Word не держит событие. Если это косяк не ваш, то (насколько мне представляется ситуация ваших проблем из того что удалось понять) - это косяк ворда.
В следующий раз старайтесь выкладывать код полностью ((сделаю предположение)даже если вы работаете в софтверной компании).
Вопрос: Событие нажатия клавиш в c#

Здравствуйте,
Подскажите пожалуйста каким образом в c# перехватить событие нажатие комбинации клавиш "CTRL+S". Есть стандартное событие windows forms "KeyPress", но оно не совсем мне подходит, так как оно ловит все нажатия клавиш, а мне надо чтобы событие возникало при нажатии клавиш "Ctrl+s".
Заранее спасибо.
Ответ:
Roman Mejtes
Serega325
пропущено...

Вот код, который реализован на данный момент. У меня есть контрол текстовый редактор, я хочу чтобы при нажатии "Ctrl+s" текст с контрола сохранялся в базу, но при таком коде, который Вы предлагаете (обработка события Control.KeyPress) событие вызывается при нажатии любых клавиш (в, м, п, в, а, р, п, alt+f4 и т.д.), а я хочу чтобы событие возникало только при нажатии "ctrl+s", т.е. сразу без фильтрации или хотя бы при нажатии "ctrl".

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

Дела вот в чем: у меня есть редактор для интерпритатора с подсветкой синтаксиса, поскольку при вводе символа вызывается кучу всяких событий, то при очень быстром наборе текста он начинает подтормаживать, поэтому я хочу уменьшить количество вызываемых событий. Например вызывать событие только при нажатии системной клавиши (alt, ctrl,shift), а не фильтровать каждую клавишу.
Вопрос: Создание и обработка событий

Всем добрый день. К данной программе нужно создать какое либо событие.

Тема: Создание и обработка событий.
Цель работы: Закрепить навыки работы с типами делегатов, научиться разрабатывать
компоненты-источники событий, а также использовать эти компоненты в программах-
клиентах.

Есть пример:

Создадим класс Cat с событием, возникающим при каждом десятке пойманных мышей:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Тип делегата для события
public delegate void MouseCaughtEvent(object sender, int miceCaughtCount);
public class Cat {
 private int miceCaughtCount;
 // событие, возникающее при каждом очередном десятке пойманных мышей
 public event MouseCaughtEvent OnEachTenCaught;
 // Поймать мышь
 public void CatchAMouse() {
 miceCaughtCount++;
 if (miceCaughtCount % 10 == 0) { // если количество кратно 10
 if (OnEachTenCaught != null) { // и если есть обработчик,
 OnEachTenCaught(this,miceCaughtCount); // то вызываем событие
 }
 }
 }
}
Продемонстрируем обработку этого события, объявив в форме один объект класса Cat и
назначив ему обработчик в событии form1_Load. Увеличение количества пойманных мышей
будем производить при нажатии кнопки button1.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Form1: System.Windows.Forms.Form {
 private Cat cat1 = new Cat(); // Наша кошка
 private Button button1; // Кнопка для ловли мышей
 // Назначение обработчика
 private void Form1_Load(object sender, EventArgs e) {
 cat1.OnEachTenCaught += new MouseCaughtEvent(cat1_OnEachTenCaught);
 }
 // Сам обработчик
 private void cat1_OnEachTenCaught(object sender, int miceCaughtCount) {
 MessageBox.Show(sender.ToString() + " – поймали еще 10 мышей!");
 }
 // Нажатие на кнопку button1
 private void button1_Click(object sender, EventArgs e) {
 cat1.CatchAMouse(); // Поймать одну мышь.
 // Каждые 10 мышей будет срабатывать обработчик
 }
}
Моя программа, в которой нужно добавить событие.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
 
 
namespace ВтораяЛабараторка
{
    class Liquid // Основной класс
    {
        public string name; // Название алкоголя 
 
        public void NameShow() // Вывод названия алкоголя
        {
            Console.WriteLine("Название алкоголя: " + name);
        }
    }
 
    class Alcohol : Liquid // Наследуемый класс
    {
        public string vol; // Крепость алкоголя.
 
        public Alcohol(string vol, string name)
        {
            this.name = name;
            this.vol = vol;
            // Приравнивание
        }
        public void VolShow() // Вывод крепости алкоголя после названия
        {
            Console.WriteLine("Крепость Алкоголя: " + vol);
        }
    }
 
 
 
    class Program
    {
        static void Main() // Добавляем несколько напитков и записываем их параметры для вывода
        {
            Alcohol drink = new Alcohol("","");
            drink.name = "Henessy Black";
            drink.vol = "40%";
            drink.NameShow(); // Выводим название напитка
            drink.VolShow(); // Выводим крепость напитка
            Console.WriteLine("-----------------");
 
            Alcohol drink2 = new Alcohol("", "");
            drink.name = "Hektors Sweet";
            drink.vol = "32%";
            drink.NameShow(); // Выводим название напитка
            drink.VolShow(); // Выводим крепость напитка
            Console.WriteLine("-----------------");
 
            Alcohol drink3 = new Alcohol("", "");
            drink.name = "Aldaris Alus";
            drink.vol = "4.5%";
            drink.NameShow(); // Выводим название напитка
            drink.VolShow(); // Выводим крепость напитка
            Console.WriteLine("-----------------");
 
            Alcohol drink4 = new Alcohol("", "");
            drink.name = "Cesu Gold 5";
            drink.vol = "3.0%";
            drink.NameShow(); // Выводим название напитка
            drink.VolShow(); // Выводим крепость напитка
            Console.WriteLine("-----------------");
 
            Alcohol drink5 = new Alcohol("", "");
            drink.name = "Vodka Nemiroff";
            drink.vol = "40%";
            drink.NameShow(); // Выводим название напитка
            drink.VolShow(); // Выводим крепость напитка
            
 
            Console.ReadLine();
        }
    }
}

буду очень рад любой помощи!!!! Спасибо!!!!
Ответ:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
          
            drink.name = "Vodka Nemiroff";
            drink.vol = 40;
            drink.minVol = 15;
            drink.BarmanLayOffEvent += new BarmanLayOffDel(drink_BarmanLayOffHandler);
        }
        Alcohol drink = new Alcohol();
 
 
        // Тип делегата для события
        public delegate void BarmanLayOffDel(object sender);
 
        class Liquid // Основной класс
        {
            public string name; // Название 
 
        }
 
        class Alcohol : Liquid // Наследуемый класс
        {
            public float vol; // Крепость алкоголя.
            public float minVol; // Мин Крепость алкоголя.
 
            public event BarmanLayOffDel BarmanLayOffEvent;
            public Alcohol()
            {
                this.name = "";
                this.vol = 0.0f;
                this.minVol = 0.0f;
            }
            public Alcohol(string name, float vol, float minVol)
            {
                this.name = name;
                this.vol = vol;
                this.minVol = minVol;
            }
            public override string ToString() // Вывод крепости алкоголя после названия
            {
                return "Название: " + name + "\nКрепость Алкоголя: " + vol + "\nМинимальная крепость Алкоголя: " + minVol;
            }
 
 
            // Бармен разбавляет алкоголь
            public void WaterDown()
            {
                this.vol-= 5.0f;
 
                // если  разбавлять дальше некуда
                if (this.vol <= this.minVol)
                {
                    if (BarmanLayOffEvent != null)
                    {
                        // то вызываем событие. бармена поймали и уволили
                        BarmanLayOffEvent(this);
                    }
                }
            }
           
 
        }
        // Сам обработчик
        private  void drink_BarmanLayOffHandler(object sender)
        {
            MessageBox.Show("Бармен был уволен " + sender.ToString());
            (sender as Alcohol).vol = 40; // замена испорченного напитка
        }
        private void button1_Click(object sender, EventArgs e)
        {          
            drink.WaterDown();          
        }
    }