Страницы

Поиск по вопросам

среда, 25 декабря 2019 г.

Как устроены, как работают и как самому сделать отменяемое событие?

#c_sharp #net #события


Например, в WinForms есть много событий, где можно вызвать e.Cancel=true и тогда
выполнение обработки события завершается.

Как оно устроеное, как работает и как самому реализовать такое событие?
    


Ответы

Ответ 1



В .NET есть стандартный класс CancelEventArgs. Если вам нужно передать в обработчик какие-то данные - создаете наследник от CancelEventArgs. Если не нужно - просто используете CancelEventArgs как есть. class MyEventArgs : CancelEventArgs { } class SomeClass { public event EventHandler SomeEvent; private bool OnSomeEvent() { var args = new MyEventArgs(); SomeEvent?.Invoke(this, args); return !args.Cancel; } public void SomeAction() { // наступило событие if (OnSomeEvent()) { // продолжить } else { // отменить } } } Если вы используете свои параметры для события, то наследоваться от CancelEventArgs необязательно - можно просто добавить bool Cancel к уже существующим данным.

Ответ 2



1) (Необязательно) В некоторых случаях, если кто-то отменил присвоение, полезно выбросить исключение, оповестив таким образом присваювающий код о отмене, хотя можно обойтись и просто проверкой удачности присвоения, или вообще проигнорировать отмену. Класс исключения, который я использую. [Serializable] /// Исключение возникает при прерывании выполнения setter для свойства public class SetterAbortException : Exception { public SetterAbortException() { } public SetterAbortException(string message) : base(message) { } public SetterAbortException(string message, Exception inner) : base(message, inner) { } protected SetterAbortException( System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } 2) Понадобится класс-потомок EventArgs содержащий флаг отмены и данные предлагаемые к присвоению. Если подходящего нет в .Net, подключенных библиотеках или вашем решении, придётся создать. public class ValueChangingEventArgs : EventArgs { public ValueChangingEventArgs(decimal newvalue) { Cancel = false; NewValue = newvalue; } public bool Cancel { get; set; } public decimal NewValue { get; private set; } } 3) Создаём EventHandler соответствующий нашему EventArgs. public delegate void ValueChangingEventHandler(object sender, ValueChangingEventArgs ea); 4) Желательно реализовать закрытый/защищенный метод вызова события. /// /// Вызов события о начале изменения значения /// /// новое значение /// Разрешение продолжить значение protected virtual bool onValueChanging(decimal value) { var ea = new ValueChangingEventArgs(value); if (ValueChanging != null) { ValueChanging(this, ea); } return !ea.Cancel; } /// /// Событие возникает при начале изменения значения свойства Value /// public event ValueChangingEventHandler ValueChanging; 5) Осталось написать свойство с выбросом исключения при отмене или без него. private decimal value; /// /// Значение параметра в единицах СИ /// public decimal Value { get { return value; } set { if (!this.value.Equals(value)) //Проверяем новое значение присваивается или нет. Проверку можно убрать, если нужно, чтобы событие срабатывало даже, когда присваивается старое значение. { if (onValueChanging(value)) { this.value = value; onValueChanged(); //Вызов события о завершении присвоения } else // Удалить если не нужно исключение throw new SetterAbortException ("Присвоение прервано"); } } }

Комментариев нет:

Отправить комментарий