| Line | Revision | Contents |
| 1 | 2 | using System; |
| 2 | using System.Collections.Generic; |
|
| 3 | using System.ComponentModel; |
|
| 4 | using System.Linq; |
|
| 5 | 3 | using System.Reflection; |
| 6 | using Microsoft.Practices.Composite.Presentation.Commands; |
|
| 7 | 2 | |
| 8 | 3 | namespace HouseOfBilz |
| 9 | 2 | { |
| 10 | public class ActiveViewModel<PropertyT> : CustomTypeDescriptor, INotifyPropertyChanged |
|
| 11 | { |
|
| 12 | private readonly Dictionary<string, object> _values = new Dictionary<string, object>(); |
|
| 13 | ||
| 14 | public ActiveViewModel() |
|
| 15 | { |
|
| 16 | if (!typeof(PropertyT).IsEnum) throw new InvalidCastException("ActiveModel<PropertyT>: PropertyT must be an enum"); |
|
| 17 | 3 | CreateCommands(); |
| 18 | 2 | } |
| 19 | ||
| 20 | 3 | public object Get(PropertyT name) { return Get(name.ToString()); } |
| 21 | 2 | public T Get<T>(PropertyT name) { return (T)Get(name); } |
| 22 | public T Get<T>(string name) { return (T)Get(name); } |
|
| 23 | public object Get(string name) |
|
| 24 | { |
|
| 25 | if (_values.ContainsKey(name)) |
|
| 26 | return _values[name]; |
|
| 27 | ||
| 28 | return null; |
|
| 29 | } |
|
| 30 | ||
| 31 | protected void Set<T>(PropertyT name, T value) { Set(name.ToString(), value); } |
|
| 32 | public void Set<T>(string name, T value) |
|
| 33 | { |
|
| 34 | if (_values.ContainsKey(name)) |
|
| 35 | _values[name] = value; |
|
| 36 | else |
|
| 37 | _values.Add(name, value); |
|
| 38 | ||
| 39 | FirePropertyChanged(name); |
|
| 40 | 5 | FireCanExecuteChanged(name); |
| 41 | 2 | } |
| 42 | ||
| 43 | protected void FirePropertyChanged(string propertyName) |
|
| 44 | { |
|
| 45 | var handlers = PropertyChanged; |
|
| 46 | if (handlers != null) |
|
| 47 | handlers(this, new PropertyChangedEventArgs(propertyName)); |
|
| 48 | } |
|
| 49 | ||
| 50 | public event PropertyChangedEventHandler PropertyChanged; |
|
| 51 | ||
| 52 | public override PropertyDescriptorCollection GetProperties() |
|
| 53 | { |
|
| 54 | return GetProperties(new Attribute[0]); |
|
| 55 | } |
|
| 56 | ||
| 57 | public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) |
|
| 58 | { |
|
| 59 | var result = new PropertyDescriptorCollection(base.GetProperties().Cast<PropertyDescriptor>().ToArray()); |
|
| 60 | ||
| 61 | 3 | PropertyNames.Union(CommandNames).Each(name => result.Add(new ViewModelProperty(name, attributes))); |
| 62 | 2 | |
| 63 | return result; |
|
| 64 | } |
|
| 65 | ||
| 66 | 3 | private const string EXECUTE_PREFIX = "Execute_"; |
| 67 | 4 | private const string CAN_EXECUTE_PREFIX = "CanExecute_"; |
| 68 | 3 | |
| 69 | private IEnumerable<string> CommandNames |
|
| 70 | { |
|
| 71 | get |
|
| 72 | { |
|
| 73 | return from method in GetType().GetMethods().Cast<MethodInfo>() |
|
| 74 | where method.Name.StartsWith(EXECUTE_PREFIX) |
|
| 75 | select method.Name.StripLeft(EXECUTE_PREFIX.Length); |
|
| 76 | } |
|
| 77 | } |
|
| 78 | ||
| 79 | 5 | private static IEnumerable<string> PropertyNames |
| 80 | 3 | { |
| 81 | get |
|
| 82 | { |
|
| 83 | return from name in Enum.GetValues(typeof(PropertyT)).Cast<PropertyT>() |
|
| 84 | select name.ToString(); |
|
| 85 | } |
|
| 86 | } |
|
| 87 | ||
| 88 | private void CreateCommands() |
|
| 89 | { |
|
| 90 | 4 | CommandNames.Each(name => Set(name, new DelegateCommand<object>(x => ExecuteCommand(name), x => CanExecuteCommand(name)))); |
| 91 | 3 | } |
| 92 | ||
| 93 | private void ExecuteCommand(string name) |
|
| 94 | { |
|
| 95 | var methodInfo = GetType().GetMethod(EXECUTE_PREFIX + name); |
|
| 96 | if (methodInfo == null) return; |
|
| 97 | ||
| 98 | methodInfo.Invoke(this, null); |
|
| 99 | } |
|
| 100 | ||
| 101 | 4 | private bool CanExecuteCommand(string name) |
| 102 | { |
|
| 103 | var methodInfo = GetType().GetMethod(CAN_EXECUTE_PREFIX + name); |
|
| 104 | 5 | if (methodInfo == null) return true; |
| 105 | ||
| 106 | return (bool)methodInfo.Invoke(this, null); |
|
| 107 | } |
|
| 108 | ||
| 109 | private void FireCanExecuteChanged(string propertyName) |
|
| 110 | { |
|
| 111 | CommandsDependentUpon(propertyName) |
|
| 112 | .Each(commandName => { |
|
| 113 | var command = Get<DelegateCommand<object>>(commandName); |
|
| 114 | if (command != null) |
|
| 115 | command.RaiseCanExecuteChanged(); |
|
| 116 | }); |
|
| 117 | ||
| 118 | } |
|
| 119 | ||
| 120 | private IEnumerable<string> CommandsDependentUpon(string propertyName) |
|
| 121 | { |
|
| 122 | foreach (var name in CommandNames) |
|
| 123 | { |
|
| 124 | var methodInfo = GetType().GetMethod(CAN_EXECUTE_PREFIX + name); |
|
| 125 | if (methodInfo == null) continue; |
|
| 126 | ||
| 127 | 7 | var dependentUpon = methodInfo.GetCustomAttributes(typeof(DependentUponAttribute), true).Cast<DependentUponAttribute>() |
| 128 | .Any(attribute => attribute.Names.Contains(propertyName)); |
|
| 129 | 5 | |
| 130 | if (dependentUpon) |
|
| 131 | yield return name; |
|
| 132 | } |
|
| 133 | 4 | } |
| 134 | ||
| 135 | 3 | private class ViewModelProperty : PropertyDescriptor |
| 136 | { |
|
| 137 | public ViewModelProperty(string name, Attribute[] attributes) |
|
| 138 | 2 | : base(name, attributes) |
| 139 | { |
|
| 140 | } |
|
| 141 | ||
| 142 | public override object GetValue(object component) |
|
| 143 | { |
|
| 144 | var viewModel = component as ActiveViewModel<PropertyT>; |
|
| 145 | 3 | if (viewModel == null) return null; |
| 146 | 2 | |
| 147 | return viewModel.Get(Name); |
|
| 148 | } |
|
| 149 | ||
| 150 | public override void SetValue(object component, object value) |
|
| 151 | { |
|
| 152 | var viewModel = component as ActiveViewModel<PropertyT>; |
|
| 153 | if (viewModel == null) return; |
|
| 154 | ||
| 155 | viewModel.Set(Name, value); |
|
| 156 | } |
|
| 157 | ||
| 158 | public override void ResetValue(object component) { SetValue(component, null); } |
|
| 159 | public override bool ShouldSerializeValue(object component) { return false; } |
|
| 160 | public override Type ComponentType { get { return typeof(ActiveViewModel<PropertyT>); } } |
|
| 161 | public override bool IsReadOnly { get { return false; } } |
|
| 162 | public override Type PropertyType { get { return typeof(object); } } |
|
| 163 | public override bool CanResetValue(object component) { return true; } |
|
| 164 | } |
|
| 165 | } |
|
| 166 | 3 | |
| 167 | 5 | [AttributeUsage(AttributeTargets.Method)] |
| 168 | 7 | public class DependentUponAttribute : Attribute |
| 169 | 5 | { |
| 170 | 7 | public DependentUponAttribute(params object[] properties) |
| 171 | 5 | { |
| 172 | Names = properties.Select(name => name.ToString()); |
|
| 173 | } |
|
| 174 | ||
| 175 | public IEnumerable<string> Names { get; private set; } |
|
| 176 | } |
|
| 177 | ||
| 178 | 3 | public static class Extensions |
| 179 | { |
|
| 180 | public static string StripLeft(this string value, int length) |
|
| 181 | { |
|
| 182 | return value.Substring(length, value.Length - length); |
|
| 183 | } |
|
| 184 | ||
| 185 | public static void Each<T>(this IEnumerable<T> list, Action<T> action) |
|
| 186 | { |
|
| 187 | foreach (var item in list) |
|
| 188 | action(item); |
|
| 189 | } |
|
| 190 | } |
|
| 191 | 2 | } |
Loggerhead 1.10 is a web-based interface for Bazaar branches