Skip to content

Commit

Permalink
Update framework references.
Browse files Browse the repository at this point in the history
  • Loading branch information
x-stars committed Feb 19, 2021
1 parent b5bbfdc commit ed89d54
Show file tree
Hide file tree
Showing 9 changed files with 365 additions and 69 deletions.
58 changes: 58 additions & 0 deletions WaveGenerator/Framework/DelegateCommand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.ComponentModel;
using System.Windows.Input;

namespace XstarS.Windows.Input
Expand Down Expand Up @@ -77,5 +78,62 @@ public override bool CanExecute(object parameter)
{
base.NotifyCanExecuteChanged();
}

/// <summary>
/// 设定在指定属性发生更改时,通知当前命令的可执行状态已更改。
/// </summary>
/// <param name="source">发出属性更改通知的事件源对象。</param>
/// <param name="propertyName">要接收更改通知的属性的名称。</param>
/// <returns>当前 <see cref="DelegateCommand"/> 实例。</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="source"/> 为 <see langword="null"/>。</exception>
public DelegateCommand ObserveCanExecute(
INotifyPropertyChanged source, string propertyName)
{
if (source is null) { throw new ArgumentNullException(nameof(source)); }
var observer = new CanExecuteObserver(this, propertyName);
source.PropertyChanged += observer.OnPropertyChanged;
return this;
}

/// <summary>
/// 提供在属性发生更改时,通知命令的可执行状态发生更改的方法。
/// </summary>
private sealed class CanExecuteObserver
{
/// <summary>
/// 表示要通知的可执行状态已更改的命令。
/// </summary>
private readonly DelegateCommand Command;

/// <summary>
/// 表示要接收更改通知的属性的名称。
/// </summary>
private readonly string PropertyName;

/// <summary>
/// 使用命令和属性的名称初始化 <see cref="CanExecuteObserver"/> 类的新实例。
/// </summary>
/// <param name="command">要通知的可执行状态已更改的命令。</param>
/// <param name="propertyName">要接收更改通知的属性的名称。</param>
public CanExecuteObserver(DelegateCommand command, string propertyName)
{
this.Command = command;
this.PropertyName = propertyName;
}

/// <summary>
/// 当指定名称的属性发生更改时,通知命令的可执行状态发生更改。
/// </summary>
/// <param name="sender">属性更改通知的事件源。</param>
/// <param name="e">提供属性更改通知的事件数据。</param>
public void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == this.PropertyName)
{
this.Command.NotifyCanExecuteChanged();
}
}
}
}
}
75 changes: 75 additions & 0 deletions WaveGenerator/Framework/EnumFlagsVectorView.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using System.Runtime.CompilerServices;

namespace XstarS.ComponentModel
{
/// <summary>
/// 提供位域枚举的向量视图的基类。
/// </summary>
/// <typeparam name="TEnum">位域枚举的类型。</typeparam>
[Serializable]
public class EnumFlagsVectorView<TEnum> : EnumViewBase<TEnum>
where TEnum : struct, Enum
{
/// <summary>
/// 初始化 <see cref="EnumFlagsVectorView{TEnum}"/> 类的新实例。
/// </summary>
public EnumFlagsVectorView() { }

/// <summary>
/// 获取或设置当前视图表示的枚举值是否包含指定的枚举位域。
/// </summary>
/// <param name="flagValue">要获取或设置的枚举位域。</param>
/// <returns>若当前视图表示的枚举值包含指定的枚举位域,
/// 则为 <see langword="true"/>;否则为 <see langword="false"/>。</returns>
public bool this[TEnum flagValue]
{
get => this.Value.HasFlag(flagValue);
set => this.SetFlag(flagValue, value);
}

/// <summary>
/// 获取当前视图表示的枚举值是否包含指定的枚举位域。
/// </summary>
/// <param name="flagName">要确定的枚举位域的名称。</param>
/// <returns>若当前视图表示的枚举值包含指定的枚举位域值,
/// 则为 <see langword="true"/>;否则为 <see langword="false"/>。</returns>
/// <exception cref="ArgumentException">
/// <paramref name="flagName"/> 不为有效的枚举值名称。</exception>
protected bool HasFlag(
[CallerMemberName] string flagName = null)
{
flagName = flagName ?? string.Empty;
var flagValue = this.ParseEnum(flagName);
return this[flagValue];
}

/// <summary>
/// 根据指示设置当前视图表示的枚举值的指定的枚举位域。
/// </summary>
/// <param name="value">指示是添加位域还是移除位域。</param>
/// <param name="flagName">要设置的枚举位域的名称。</param>
/// <exception cref="ArgumentException">
/// <paramref name="flagName"/> 不为有效的枚举值名称。</exception>
protected void SetFlag(bool value,
[CallerMemberName] string flagName = null)
{
flagName = flagName ?? string.Empty;
var flagValue = this.ParseEnum(flagName);
this[flagValue] = value;
}

/// <summary>
/// 根据指示设置当前视图表示的枚举值的指定的枚举位域。
/// </summary>
/// <param name="flagValue">要设置的枚举位域。</param>
/// <param name="value">指示是否设置枚举值。</param>
protected virtual void SetFlag(TEnum flagValue, bool value)
{
var iValue = ((IConvertible)this.Value).ToUInt64(null);
var iFlag = ((IConvertible)flagValue).ToUInt64(null);
if (value) { iValue |= iFlag; } else { iValue &= ~iFlag; }
this.Value = (TEnum)Enum.ToObject(typeof(TEnum), iValue);
}
}
}
90 changes: 90 additions & 0 deletions WaveGenerator/Framework/EnumListView.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;

namespace XstarS.ComponentModel
{
/// <summary>
/// 表示枚举的列表视图。
/// </summary>
/// <typeparam name="TEnum">枚举的类型。</typeparam>
[Serializable]
[DebuggerDisplay("Selected = {" + nameof(SelectedItem) + "}")]
public class EnumListView<TEnum> : ReadOnlyObservableCollection<TEnum>
where TEnum : struct, Enum
{
/// <summary>
/// 表示当前视图选中的枚举值的索引。
/// </summary>
private int ItemIndex;

/// <summary>
/// 初始化 <see cref="EnumListView{TEnum}"/> 类的新实例。
/// </summary>
public EnumListView() : base(EnumListView<TEnum>.CreateItems()) { }

/// <summary>
/// 创建当前枚举类型中所有枚举值的集合。
/// </summary>
/// <returns>当前枚举类型中所有枚举值的集合。</returns>
private static ObservableCollection<TEnum> CreateItems()
{
var values = (TEnum[])Enum.GetValues(typeof(TEnum));
return new ObservableCollection<TEnum>(values);
}

/// <summary>
/// 获取或设置当前视图选中的枚举值的索引。
/// </summary>
/// <returns>当前视图表示的枚举值的索引。</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="value"/> 不为小于当前枚举值数量的非负整数。</exception>
public int SelectedIndex
{
get => this.ItemIndex;
set => this.SelectIndex(value);
}

/// <summary>
/// 获取或设置当前视图选中的枚举值。
/// </summary>
/// <returns>当前视图选中的枚举值。</returns>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="value"/> 不为有效的枚举值。</exception>
public TEnum SelectedItem
{
get => this[this.SelectedIndex];
set => this.SelectedIndex = this.IndexOf(value);
}

/// <summary>
/// 设置当前视图选中的枚举值的索引。
/// </summary>
/// <param name="index">要设置的枚举值的索引。</param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="index"/> 不为小于当前枚举值数量的非负整数。</exception>
protected virtual void SelectIndex(int index)
{
if ((index < 0) || (index >= this.Count))
{
throw new ArgumentOutOfRangeException(nameof(index));
}
if (this.ItemIndex != index)
{
this.ItemIndex = index;
this.NotifyPropertyChanged(nameof(this.SelectedIndex));
this.NotifyPropertyChanged(nameof(this.SelectedItem));
}
}

/// <summary>
/// 通知指定属性的值已更改。
/// </summary>
/// <param name="propertyName">已更改属性的名称。</param>
protected void NotifyPropertyChanged(string propertyName)
{
this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
}
}
42 changes: 13 additions & 29 deletions WaveGenerator/Framework/EnumVectorView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace XstarS.ComponentModel
/// </summary>
/// <typeparam name="TEnum">枚举的类型。</typeparam>
[Serializable]
public class EnumVectorView<TEnum> : ObservableDataObject
public class EnumVectorView<TEnum> : EnumViewBase<TEnum>
where TEnum : struct, Enum
{
/// <summary>
Expand All @@ -24,18 +24,8 @@ public EnumVectorView() { }
/// 则为 <see langword="true"/>;否则为 <see langword="false"/>。</returns>
public bool this[TEnum enumValue]
{
get => object.Equals(this.Value, enumValue);
set { if (value) { this.Value = enumValue; } }
}

/// <summary>
/// 获取或设置当前视图表示的枚举值。
/// </summary>
/// <returns>当前视图表示的枚举值。</returns>
public TEnum Value
{
get => this.GetProperty<TEnum>();
set => this.SetProperty(value);
get => this.Value.Equals(enumValue);
set => this.SetEnum(enumValue, value);
}

/// <summary>
Expand All @@ -50,7 +40,8 @@ protected bool IsEnum(
[CallerMemberName] string enumName = null)
{
enumName = enumName ?? string.Empty;
return this[(TEnum)Enum.Parse(typeof(TEnum), enumName)];
var enumValue = this.ParseEnum(enumName);
return this[enumValue];
}

/// <summary>
Expand All @@ -60,29 +51,22 @@ protected bool IsEnum(
/// <param name="enumName">要设置的枚举值的名称。</param>
/// <exception cref="ArgumentException">
/// <paramref name="enumName"/> 不为有效的枚举值名称。</exception>
protected virtual void SetEnum(bool value,
protected void SetEnum(bool value,
[CallerMemberName] string enumName = null)
{
enumName = enumName ?? string.Empty;
this[(TEnum)Enum.Parse(typeof(TEnum), enumName)] = value;
var enumValue = this.ParseEnum(enumName);
this[enumValue] = value;
}

/// <summary>
/// 设置指定属性的值
/// 根据指示设置当前视图表示的枚举值
/// </summary>
/// <typeparam name="T">属性的类型。</typeparam>
/// <param name="value">属性的新值。</param>
/// <param name="propertyName">要设置值的属性的名称。</param>
protected override void SetProperty<T>(T value,
[CallerMemberName] string propertyName = null)
/// <param name="enumValue">要设置的枚举值。</param>
/// <param name="value">指示是否设置枚举值。</param>
protected virtual void SetEnum(TEnum enumValue, bool value)
{
base.SetProperty(value, propertyName);
if (propertyName == nameof(this.Value))
{
var enumNames = Enum.GetNames(typeof(TEnum));
Array.ForEach(enumNames, this.NotifyPropertyChanged);
this.NotifyPropertyChanged(ObservableDataObject.IndexerName);
}
if (value) { this.Value = enumValue; }
}
}
}
62 changes: 62 additions & 0 deletions WaveGenerator/Framework/EnumViewBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Diagnostics;

namespace XstarS.ComponentModel
{
/// <summary>
/// 提供枚举的视图的抽象基类。
/// </summary>
/// <typeparam name="TEnum">枚举的类型。</typeparam>
[Serializable]
[DebuggerDisplay("Value = {" + nameof(Value) + "}")]
public abstract class EnumViewBase<TEnum> : ObservableDataObject
where TEnum : struct, Enum
{
/// <summary>
/// 初始化 <see cref="EnumVectorView{TEnum}"/> 类的新实例。
/// </summary>
protected EnumViewBase() { }

/// <summary>
/// 获取或设置当前视图表示的枚举值。
/// </summary>
/// <returns>当前视图表示的枚举值。</returns>
public TEnum Value
{
get => this.GetProperty<TEnum>();
set => this.SetEnumValue(value);
}

/// <summary>
/// 将当前枚举类型的枚举名称转换为等效的枚举值。
/// </summary>
/// <param name="name">要转换的枚举值的名称。</param>
/// <returns>名为 <paramref name="name"/> 的枚举值。</returns>
protected TEnum ParseEnum(string name)
{
return (TEnum)Enum.Parse(typeof(TEnum), name);
}

/// <summary>
/// 设置当前视图表示的枚举值。
/// </summary>
/// <param name="value">要设置的枚举值。</param>
protected virtual void SetEnumValue(TEnum value)
{
var enumValue = this.Value;
this.SetProperty(value, nameof(this.Value));
var valueChanged = !object.Equals(enumValue, value);
if (valueChanged) { this.NotifyEnumPropertiesChanged(); }
}

/// <summary>
/// 通知所有枚举值对应的属性的值已更改。
/// </summary>
protected void NotifyEnumPropertiesChanged()
{
var enumNames = Enum.GetNames(typeof(TEnum));
Array.ForEach(enumNames, this.NotifyPropertyChanged);
this.NotifyPropertyChanged(ObservableDataObject.IndexerName);
}
}
}
4 changes: 3 additions & 1 deletion WaveGenerator/Framework/ObservableDataObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ protected virtual void SetProperty<T>(T value,
[CallerMemberName] string propertyName = null)
{
propertyName = propertyName ?? string.Empty;
var property = this.GetProperty<T>(propertyName);
this.Properties[propertyName] = (object)value;
this.NotifyPropertyChanged(propertyName);
var propertyChanged = !RuntimeHelpers.Equals(property, value);
if (propertyChanged) { this.NotifyPropertyChanged(propertyName); }
}

/// <summary>
Expand Down
Loading

0 comments on commit ed89d54

Please sign in to comment.