using System.ComponentModel; using System.Runtime.CompilerServices; namespace HKW.HKWUtils.Observable; /// /// 可观察对象 /// 示例: /// { /// int _value = 0; /// public int Value /// { /// get => _value; /// set => SetProperty(ref _value, value); /// } /// }]]> /// public abstract class ObservableClass : INotifyPropertyChanging, INotifyPropertyChanged, INotifyPropertyChangingX, INotifyPropertyChangedX where TObject : ObservableClass { public ObservableClass() { if (GetType() != typeof(TObject)) throw new InvalidCastException( $"Inconsistency between target type [{GetType().FullName}] and generic type [{typeof(TObject).FullName}]" ); } #region OnPropertyChange /// /// 设置属性值 /// /// 值 /// 新值 /// 属性名称 /// 成功为 失败为 [MethodImpl(MethodImplOptions.AggressiveInlining)] protected virtual bool SetProperty( ref TValue value, TValue newValue, [CallerMemberName] string propertyName = null! ) { if (EqualityComparer.Default.Equals(value, newValue) is true) return false; var oldValue = value; if (OnPropertyChanging(oldValue, newValue, propertyName)) return false; value = newValue; OnPropertyChanged(oldValue, newValue, propertyName); return true; } /// /// 属性改变前 /// /// 旧值 /// 新值 /// 属性名称 /// 取消为 否则为 [MethodImpl(MethodImplOptions.AggressiveInlining)] protected virtual bool OnPropertyChanging( object? oldValue, object? newValue, [CallerMemberName] string propertyName = null! ) { PropertyChanging?.Invoke(this, new(propertyName)); if (PropertyChangingX is null) return false; var e = new PropertyChangingXEventArgs(propertyName, oldValue, newValue); PropertyChangingX?.Invoke((TObject)this, e); if (e.Cancel) PropertyChanged?.Invoke(this, new(propertyName)); return e.Cancel; } /// /// 属性改变后 /// /// 旧值 /// 新值 /// 属性名称 [MethodImpl(MethodImplOptions.AggressiveInlining)] protected virtual void OnPropertyChanged( object? oldValue, object? newValue, [CallerMemberName] string propertyName = null! ) { PropertyChanged?.Invoke(this, new(propertyName)); PropertyChangedX?.Invoke((TObject)this, new(propertyName, oldValue, newValue)); } #endregion #region Event /// public event PropertyChangingEventHandler? PropertyChanging; /// public event PropertyChangedEventHandler? PropertyChanged; /// public event PropertyChangingXEventHandler? PropertyChangingX; /// public event PropertyChangedXEventHandler? PropertyChangedX; #endregion }