Last active
December 5, 2016 03:51
-
-
Save nexpr/7c1956bbed09de98b0426806c15be125 to your computer and use it in GitHub Desktop.
BindingDataBase (WPF ViewModel Base)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| namespace liblib.wpf | |
| { | |
| [AttributeUsage(AttributeTargets.Property)] | |
| public class AutoValidateTarget : Attribute | |
| { | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections; | |
| using System.Collections.Generic; | |
| using System.ComponentModel; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Threading.Tasks; | |
| namespace liblib.wpf | |
| { | |
| public abstract class BindingDataBase : INotifyPropertyChanged, INotifyDataErrorInfo | |
| { | |
| /// <summary> | |
| /// エラー管理 | |
| /// </summary> | |
| protected Map<string, HashSet<string>> errors { get; } | |
| = new Map<string, HashSet<string>>(() => new HashSet<string>()); | |
| /// <summary> | |
| /// プロパティの実体 | |
| /// </summary> | |
| protected Dictionary<string, object> entities { get; } | |
| = new Dictionary<string, object>(); | |
| /// <summary> | |
| /// エラーを含むか | |
| /// </summary> | |
| public bool HasErrors => this.errors.Any(e => e.Value.Count > 0); | |
| public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; | |
| public event PropertyChangedEventHandler PropertyChanged; | |
| /// <summary> | |
| /// 指定プロパティのエラー取得 | |
| /// </summary> | |
| /// <param name="propertyName"></param> | |
| /// <returns></returns> | |
| public IEnumerable GetErrors(string propertyName) => this.errors[propertyName]; | |
| /// <summary> | |
| /// プロパティの変更を通知する | |
| /// </summary> | |
| /// <param name="property_name"></param> | |
| protected void notifyPropertyChanged(string property_name) | |
| => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property_name)); | |
| /// <summary> | |
| /// エラーの変更を通知する | |
| /// </summary> | |
| /// <param name="property_name"></param> | |
| protected void notifyErrorsChanged(string property_name) | |
| => this.ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(property_name)); | |
| /// <summary> | |
| /// 指定プロパティ名の実体を返す | |
| /// </summary> | |
| /// <typeparam name="T"></typeparam> | |
| /// <param name="property_name"></param> | |
| /// <param name="default_value"></param> | |
| /// <returns></returns> | |
| protected T getValue<T>(string property_name, T default_value = default(T)) | |
| { | |
| if (!this.entities.ContainsKey(property_name)) | |
| { | |
| this.entities[property_name] = default_value; | |
| } | |
| return (T)entities[property_name]; | |
| } | |
| /// <summary> | |
| /// 指定プロパティ名に値を保存 | |
| /// </summary> | |
| /// <param name="property_name"></param> | |
| /// <param name="value"></param> | |
| protected void setValue(string property_name, object value) | |
| { | |
| object old_value; | |
| if (this.entities.TryGetValue(property_name, out old_value) && Equals(old_value, value)) | |
| { | |
| return; | |
| } | |
| object correct_value; | |
| HashSet<string> errors = new HashSet<string>(); | |
| if (this.checkValidity(property_name, value, old_value, out correct_value, ref errors)) | |
| { | |
| // valid | |
| this.entities[property_name] = correct_value; | |
| this.errors[property_name].Clear(); | |
| this.notifyPropertyChanged(property_name); | |
| this.notifyErrorsChanged(property_name); | |
| } | |
| else | |
| { | |
| // invalid | |
| this.entities[property_name] = correct_value; | |
| this.errors[property_name] = errors; | |
| this.notifyPropertyChanged(property_name); | |
| this.notifyErrorsChanged(property_name); | |
| } | |
| } | |
| /// <summary> | |
| /// データのチェック | |
| /// </summary> | |
| /// <param name="property_name"></param> | |
| /// <param name="value"></param> | |
| /// <param name="corrected_value"></param> | |
| /// <param name="errors"></param> | |
| /// <returns></returns> | |
| protected virtual bool checkValidity(string property_name, object value, object old_value, out object correct_value, ref HashSet<string> errors) | |
| { | |
| correct_value = value; | |
| return true; | |
| } | |
| /// <summary> | |
| /// AutoValidateAttribute 付きのプロパティをまとめてエラーチェック | |
| /// </summary> | |
| /// <returns></returns> | |
| protected bool reportValidity() | |
| { | |
| var valid = true; | |
| foreach (var property_info in this.GetType().GetProperties()) | |
| { | |
| if (Attribute.GetCustomAttribute(property_info, typeof(AutoValidateTarget)) != null) | |
| { | |
| var value = property_info.GetValue(this); | |
| object correct_value; | |
| HashSet<string> errors = new HashSet<string>(); | |
| var name = property_info.Name; | |
| if (this.checkValidity(name, value, value, out correct_value, ref errors)) | |
| { | |
| // valid | |
| this.entities[name] = correct_value; | |
| this.errors[name].Clear(); | |
| this.notifyPropertyChanged(name); | |
| this.notifyErrorsChanged(name); | |
| } | |
| else | |
| { | |
| // invalid | |
| this.entities[name] = correct_value; | |
| this.errors[name] = errors; | |
| this.notifyPropertyChanged(name); | |
| this.notifyErrorsChanged(name); | |
| valid = false; | |
| } | |
| } | |
| } | |
| return valid; | |
| } | |
| /// <summary> | |
| /// 規則に沿った名前のコマンドは自動でコマンド生成する | |
| /// </summary> | |
| protected void initCommands() | |
| { | |
| foreach (var property in this.GetType().GetProperties()) | |
| { | |
| var lower_name = property.Name.ToLower(); | |
| if (lower_name.EndsWith("_command") && property.PropertyType == typeof(DelegateCommand)) | |
| { | |
| var binding_flag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase; | |
| var method = this.GetType().GetMethod(lower_name.Replace("_command", "_Execute"), binding_flag); | |
| if (method == null) | |
| { | |
| continue; | |
| } | |
| var method_delegate = (Action<object>)Delegate.CreateDelegate(typeof(Action<object>), this, method); | |
| var check_method = this.GetType().GetMethod(lower_name.Replace("_command", "_CanExecute"), binding_flag); | |
| if (check_method == null) | |
| { | |
| property.SetValue(this, new DelegateCommand(method_delegate)); | |
| } | |
| else | |
| { | |
| var check_method_delegate = (Func<object, bool>)Delegate.CreateDelegate(typeof(Func<object, bool>), this, check_method); | |
| property.SetValue(this, new DelegateCommand(method_delegate, check_method_delegate)); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Windows.Input; | |
| namespace liblib.wpf | |
| { | |
| public class DelegateCommand : ICommand | |
| { | |
| private Action<object> execute { get; set; } | |
| private Func<object, bool> canExecute { get; set; } | |
| public event EventHandler CanExecuteChanged | |
| { | |
| add { CommandManager.RequerySuggested += value; } | |
| remove { CommandManager.RequerySuggested -= value; } | |
| } | |
| public DelegateCommand(Action<object> execute, Func<object, bool> canExecute = null) | |
| { | |
| this.execute = execute; | |
| this.canExecute = canExecute; | |
| } | |
| public bool CanExecute(object parameter) | |
| { | |
| return this.canExecute?.Invoke(parameter) ?? true; | |
| } | |
| public void Execute(object parameter) | |
| { | |
| this.execute(parameter); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Threading.Tasks; | |
| namespace liblib | |
| { | |
| public class Map<TKey, TValue> : Dictionary<TKey, TValue> | |
| { | |
| Func<TValue> default_value_generator { get; } | |
| bool create_value_if_not_exist { get; } | |
| public Map(bool create_value_if_not_exist = true) | |
| { | |
| this.default_value_generator = () => default(TValue); | |
| this.create_value_if_not_exist = create_value_if_not_exist; | |
| } | |
| public Map(Func<TValue> default_value_generator, bool set_with_get = true) | |
| { | |
| this.default_value_generator = default_value_generator; | |
| this.create_value_if_not_exist = create_value_if_not_exist; | |
| } | |
| public new TValue this[TKey key] | |
| { | |
| get | |
| { | |
| if (key == null || !this.ContainsKey(key)) | |
| { | |
| var value = this.default_value_generator(); | |
| if (key != null && this.create_value_if_not_exist) | |
| { | |
| base[key] = value; | |
| } | |
| return value; | |
| } | |
| else | |
| { | |
| return base[key]; | |
| } | |
| } | |
| set | |
| { | |
| base[key] = value; | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment