속성의 값이 변경되면 이벤트를 발생하고 처리를 해보자.
event 키워드를 사용하여 이벤트를 선언 하고
이벤트 대리자를(핸들러 메서드 형식) 지정 한다.
public event EventHandler ValueChanged;
대리자는 반환값이 없고(void) 이벤트 발생 객체 와 이벤트 데이터를 인자로 한다.
public delegate void EventHandler(object sender, EventArgs e);
이 형식을 무시해도 되지만 MS 가이드를 따르도록 한다.
이벤트 핸들러가 void가 아니면 의미도 이상하다.
다음은 이벤트 선언과 발생의 코드 이다.
class Item { public event EventHandler ValueChanged; private int value; public int Value { get => this.value; set { if (this.value != value) { this.value = value; OnValueChanged(EventArgs.Empty); } } } protected virtual void OnValueChanged(EventArgs e) { this.ValueChanged?.Invoke(this, e); } }
속성 값 Value의 값이 변경 되었을때 이벤트를 발생한다.
Null 조건 연산자를 사용하여 스레드로부터 안전한방식으로 대리자를 호출한다.
상속을 고려하지 않는다면 OnValueChanged 메서드를 전용(private) 으로 작성해도 무관하다.
다음은 이벤트처리 코드 이다.
Item item = new Item(); item.ValueChanged += (s, e) => { Console.WriteLine($"new value: {item.Value}"); }; item.Value = 10;
다음은 조금 수정하여 이벤트 데이터를 사용하여 변경전값과 현재값을 전달한다.
이벤트 데이터 정의:
class ValueChangedEventArgs : EventArgs { public int OldValue { get; } public int NewValue { get; } public ValueChangedEventArgs(int oldValue, int newValue) { this.OldValue = oldValue; this.NewValue = newValue; } }
이벤트 데이터 사용:
class Item { public event EventHandler<ValueChangedEventArgs> ValueChanged; private int value; public int Value { get => this.value; set { if (this.value != value) { var oldValue = this.value; this.value = value; OnValueChanged(new ValueChangedEventArgs(oldValue, this.value)); } } } protected virtual void OnValueChanged(ValueChangedEventArgs e) { this.ValueChanged?.Invoke(this, e); } }
이벤트 핸들러에서 데이터 사용:
Item item = new Item(); item.ValueChanged += (s, e) => { Console.WriteLine($"old value: {e.OldValue}, new value: {e.NewValue}"); }; item.Value = 10;
이번에는 여러 속성에서 사용 할 수 있도록 변경 한다.
속성명을 알아내기 위해 CallerMemberName Attribute 를 사용 했다.
수정된 전체 코드:
class PropertyValueChangedEventArgs : EventArgs { public string PropertyName { get; } public object OldValue { get; } public object NewValue { get; } public PropertyValueChangedEventArgs(string propertyName, object oldValue, object newValue) { this.PropertyName = propertyName; this.OldValue = oldValue; this.NewValue = newValue; } } class Item { public event EventHandler<PropertyValueChangedEventArgs> PropertyValueChanged; private int intValue; public int IntValue { get => this.intValue; set { if (this.intValue != value) { var oldValue = this.intValue; this.intValue = value; OnPropertyValueChanged(oldValue, this.intValue); } } } private string strValue; public string StrValue { get => this.strValue; set { if (this.strValue != value) { var oldValue = this.strValue; this.strValue = value; OnPropertyValueChanged(oldValue, this.strValue); } } } private void OnPropertyValueChanged( object oldValue, object newValue, [CallerMemberName] string memberName = "") { this.PropertyValueChanged?.Invoke(this, new PropertyValueChangedEventArgs(memberName, oldValue, newValue)); } } class Program { static void Main(string[] args) { Item item = new Item(); item.PropertyValueChanged += (s, e) => { Console.WriteLine($"property name: {e.PropertyName} old value: {e.OldValue}, new value: {e.NewValue}"); }; item.IntValue = 10; } }