PageRenderTime 66ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/MVVMSidekick/MVVMSidekick.Shared/ViewModels.cs

https://github.com/zoujuny/MVVM-Sidekick
C# | 2346 lines | 1300 code | 507 blank | 539 comment | 116 complexity | 65270fa54cf7240b7a9a386f48dc5e56 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.ComponentModel;
  6. using System.Linq.Expressions;
  7. using System.Runtime.Serialization;
  8. using System.Reflection;
  9. using System.Threading.Tasks;
  10. using System.Threading;
  11. using System.Windows.Input;
  12. using MVVMSidekick.Commands;
  13. using System.Runtime.CompilerServices;
  14. using MVVMSidekick.Reactive;
  15. using System.Collections.ObjectModel;
  16. using System.Reactive.Linq;
  17. using System.Reactive.Threading.Tasks;
  18. #if NETFX_CORE
  19. using Windows.UI.Xaml.Controls;
  20. using System.Collections.Concurrent;
  21. #elif WPF
  22. using System.Windows;
  23. using System.Windows.Controls;
  24. using System.Windows.Data;
  25. using System.Collections.Concurrent;
  26. using System.Windows.Navigation;
  27. using MVVMSidekick.Views;
  28. using System.Windows.Controls.Primitives;
  29. using MVVMSidekick.Utilities;
  30. using System.Windows.Threading;
  31. #elif SILVERLIGHT_5||SILVERLIGHT_4
  32. using System.Windows;
  33. using System.Windows.Controls;
  34. using System.Windows.Data;
  35. using System.Windows.Navigation;
  36. using System.Windows.Controls.Primitives;
  37. using System.Windows.Threading;
  38. #elif WINDOWS_PHONE_8||WINDOWS_PHONE_7
  39. using System.Windows;
  40. using System.Windows.Controls;
  41. using Microsoft.Phone.Controls;
  42. using System.Windows.Data;
  43. using System.Windows.Navigation;
  44. using System.Windows.Controls.Primitives;
  45. using System.Windows.Threading;
  46. #endif
  47. namespace MVVMSidekick
  48. {
  49. namespace ViewModels
  50. {
  51. using MVVMSidekick.Utilities;
  52. using MVVMSidekick.Views;
  53. using MVVMSidekick.EventRouting;
  54. using System.Reactive.Disposables;
  55. /// <summary>
  56. /// <para>A ViewModel by default, with basic implement of name-value container.</para>
  57. /// <para>缺省的 ViewModel。可以用作最简单的字典绑定</para>
  58. /// </summary>
  59. public class ViewModel : ViewModelBase<ViewModel>
  60. {
  61. }
  62. /// <summary>
  63. /// <para>Base type of bindable model.</para>
  64. /// <para>ViewModel 基类</para>
  65. /// </summary>
  66. [DataContract]
  67. public abstract class BindableBase
  68. : DisposeGroupBase, INotifyPropertyChanged, IBindable
  69. {
  70. protected override void Dispose(bool disposing)
  71. {
  72. base.Dispose(disposing);
  73. }
  74. protected event EventHandler<DataErrorsChangedEventArgs> _ErrorsChanged;
  75. protected internal void RaiseErrorsChanged(string propertName)
  76. {
  77. if (_ErrorsChanged != null)
  78. {
  79. _ErrorsChanged(this, new DataErrorsChangedEventArgs(propertName));
  80. }
  81. }
  82. abstract public String BindableInstanceId { get; }
  83. public override string ToString()
  84. {
  85. return string.Format("Id {0} of {1} ({2})", BindableInstanceId, base.GetType().Name, base.ToString());
  86. }
  87. private bool _IsValidationActivated = false;
  88. /// <summary>
  89. /// <para>Gets ot sets if the validation is activatied. This is a flag only, internal logic is not depend on this.</para>
  90. /// <para>读取/设置 此模型是否激活验证。这只是一个标记,内部逻辑并没有参考这个值</para>
  91. /// </summary>
  92. public bool IsValidationActivated
  93. {
  94. get { return _IsValidationActivated; }
  95. set { _IsValidationActivated = value; }
  96. }
  97. private bool _IsNotificationActivated = true;
  98. /// <summary>
  99. /// <para>Gets ot sets if the property change notification is activatied. </para>
  100. /// <para>读取/设置 此模型是否激活变化通知</para>
  101. /// </summary>
  102. public bool IsNotificationActivated
  103. {
  104. get { return (!IsInDesignMode) ? _IsNotificationActivated : false; }
  105. set { _IsNotificationActivated = value; }
  106. }
  107. public static bool IsInDesignMode { get { return Utilities.Runtime.IsInDesignMode; } }
  108. ///// <summary>
  109. ///// <para>0 for not disposed, 1 for disposed</para>
  110. ///// <para>0 表示没有被Dispose 1 反之</para>
  111. ///// </summary>
  112. //private int disposedFlag = 0;
  113. #region Index and property names/索引与字段名
  114. /// <summary>
  115. /// <para>Get all property names that were defined in subtype, or added objectly in runtime</para>
  116. /// <para>取得本VM实例已经定义的所有字段名。其中包括静态声明的和动态添加的。</para>
  117. /// </summary>
  118. /// <returns>String[] Property names/字段名数组 </returns>
  119. public abstract string[] GetFieldNames();
  120. ///// <summary>
  121. ///// <para>Gets or sets poperty values by property name index.</para>
  122. ///// <para>使用索引方式取得/设置字段值</para>
  123. ///// </summary>
  124. ///// <param name="name">Property name/字段名</param>
  125. ///// <returns>Property value/字段值</returns>
  126. public abstract object this[string name] { get; set; }
  127. #endregion
  128. #region Propery Changed Logic/ Propery Changed事件相关逻辑
  129. protected internal void RaisePropertyChanged(Func<PropertyChangedEventArgs> lazyEAFactory)
  130. {
  131. if (this.PropertyChanged != null)
  132. {
  133. var ea = lazyEAFactory();
  134. this.PropertyChanged(this, ea);
  135. }
  136. }
  137. /// <summary>
  138. ///<para>Event that raised when properties were changed and Notification was activited</para>
  139. ///<para> VM属性任何绑定用值被修改后,在启用通知情况下触发此事件</para>
  140. /// </summary>
  141. public event PropertyChangedEventHandler PropertyChanged;
  142. #endregion
  143. #region 验证与错误相关逻辑
  144. protected bool CheckError(Func<Boolean> test, string errorMessage)
  145. {
  146. var rval = test();
  147. if (rval)
  148. {
  149. SetErrorAndTryNotify(errorMessage);
  150. }
  151. return rval;
  152. }
  153. ///// <summary>
  154. ///// 验证错误内容
  155. ///// </summary>
  156. //string IDataErrorInfo.Error
  157. //{
  158. // get
  159. // {
  160. // return GetError();
  161. // }
  162. //}
  163. /// <summary>
  164. /// <para>Gets the validate error of this model </para>
  165. /// <para>取得错误内容</para>
  166. /// </summary>
  167. /// <returns>Error string/错误内容字符串</returns>
  168. public abstract string Error { get; }
  169. /// <summary>
  170. /// <para>Sets the validate error of this model </para>
  171. /// <para>设置错误内容</para>
  172. /// </summary>
  173. /// <returns>Error string/错误内容字符串</returns>
  174. protected abstract void SetError(string value);
  175. /// <summary>
  176. /// <para>Sets the validate error of this model and notify </para>
  177. /// <para>设置错误内容并且尝试用事件通知</para>
  178. /// </summary>
  179. /// <returns>Error string/错误内容字符串</returns>
  180. protected abstract void SetErrorAndTryNotify(string value);
  181. /// <summary>
  182. /// <para>Gets validate error string of this field</para>
  183. /// <para>取得对于每个字段,验证失败所产生的错误信息</para>
  184. /// </summary>
  185. /// <param name="propertyName">Property Name of error /要检查错误的属性名</param>
  186. /// <returns>Rrror string /错误字符串</returns>
  187. protected abstract string GetColumnError(string propertyName);
  188. #endregion
  189. // public abstract bool IsUIBusy { get; set; }
  190. public abstract EventRouter EventRouter { get; set; }
  191. }
  192. /// <summary>
  193. /// <para>Extension methods of models</para>
  194. /// <para>为Model增加的一些快捷方法</para>
  195. /// </summary>
  196. public static class BindableBaseExtensions
  197. {
  198. /// <summary>
  199. /// <para>Config Value Container with delegate</para>
  200. /// <para>使用连续的API设置ValueContainer的一些参数</para>
  201. /// </summary>
  202. /// <typeparam name="TProperty">ValueContainer内容的类型</typeparam>
  203. /// <param name="target">ValueContainer的配置目标实例</param>
  204. /// <param name="action">配置内容</param>
  205. /// <returns>ValueContainer的配置目标实例</returns>
  206. public static ValueContainer<TProperty> Config<TProperty>(this ValueContainer<TProperty> target, Action<ValueContainer<TProperty>> action)
  207. {
  208. action(target);
  209. return target;
  210. }
  211. /// <summary>
  212. /// <para>Add Idisposeable to model's despose action list</para>
  213. /// <para>将IDisposable 对象注册到VM中的销毁对象列表。</para>
  214. /// </summary>
  215. /// <typeparam name="T">Type of Model /Model的类型</typeparam>
  216. /// <param name="item">IDisposable Inastance/IDisposable实例</param>
  217. /// <param name="vm">Model instance /Model 实例</param>
  218. /// <returns></returns>
  219. public static T DisposeWith<T>(this T item, IDisposeGroup tg, string comment = "", [CallerMemberName] string caller = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = -1) where T : IDisposable
  220. {
  221. tg.AddDisposable(item, comment, caller, file, line);
  222. return item;
  223. }
  224. public static ValueContainer<T> Initialize<T>(this BindableBase model, string propertyName, ref Property<T> reference, ref Func<BindableBase, ValueContainer<T>> locator, Func<T> defaultValueFactory = null)
  225. {
  226. if (reference == null)
  227. reference = new Property<T> { LocatorFunc = locator };
  228. if (reference.Container == null)
  229. {
  230. reference.Container = new ValueContainer<T>(propertyName, model);
  231. if (defaultValueFactory != null)
  232. {
  233. reference.Container.Value = defaultValueFactory();
  234. }
  235. }
  236. return reference.Container;
  237. }
  238. public static ValueContainer<T> Initialize<T>(this BindableBase model, string propertyName, ref Property<T> reference, ref Func<BindableBase, ValueContainer<T>> locator, Func<BindableBase, T> defaultValueFactory = null)
  239. {
  240. return Initialize(model, propertyName, ref reference, ref locator, () => (defaultValueFactory != null) ? defaultValueFactory(model) : default(T));
  241. }
  242. }
  243. /// <summary>
  244. /// <para>A slot to place the value container field and value container locator.</para>
  245. /// <para>属性定义。一个属性定义包括一个创建/定位属性“值容器”的静态方法引用,和一个缓存该方法执行结果“值容器”的槽位</para>
  246. /// </summary>
  247. /// <typeparam name="TProperty">Type of the property value /属性的类型</typeparam>
  248. public class Property<TProperty>
  249. {
  250. public Property()
  251. {
  252. }
  253. /// <summary>
  254. /// <para>Locate or create the value container of this model intances</para>
  255. /// <para>通过定位方法定位本Model实例中的值容器</para>
  256. /// </summary>
  257. /// <param name="model">Model intances/model 实例</param>
  258. /// <returns>Value Container of this property/值容器</returns>
  259. public ValueContainer<TProperty> LocateValueContainer(BindableBase model)
  260. {
  261. return LocatorFunc(model);
  262. }
  263. /// <summary>
  264. /// <para>Gets sets the factory to locate/create value container of this model instance</para>
  265. /// <para>读取/设置定位值容器用的方法。</para>
  266. /// </summary>
  267. public Func<BindableBase, ValueContainer<TProperty>> LocatorFunc
  268. {
  269. internal get;
  270. set;
  271. }
  272. /// <summary>
  273. /// <para>Gets or sets Value Container, it can be recently create and cached here,by LocatorFunc </para>
  274. /// <para>读取/设置值容器,这事值容器LocatorFunc创建值容器并且缓存的位置 </para>
  275. /// </summary>
  276. public ValueContainer<TProperty> Container
  277. {
  278. get;
  279. set;
  280. }
  281. }
  282. /// <summary>
  283. /// <para>Value Container, holds the value of certain field, with notifition /and compare support</para>
  284. /// <para>值容器</para>
  285. /// </summary>
  286. /// <typeparam name="TProperty">Type of the property value /属性的类型</typeparam>
  287. public class ValueContainer<TProperty> : IErrorInfo, IValueCanSet<TProperty>, IValueCanGet<TProperty>, IValueContainer
  288. {
  289. #region Constructors /构造器
  290. /// <summary>
  291. /// <para>Create a new Value Container</para>
  292. /// <para>创建属性值容器</para>
  293. /// </summary>
  294. /// <param name="model">
  295. /// <para>The model that Value Container will be held with.</para>
  296. /// <para>所属的model实例</para>
  297. /// </param>
  298. /// <param name="info">Property name/属性名</param>
  299. /// <param name="initValue">The first value of this container/初始值</param>
  300. public ValueContainer(string info, BindableBase model, TProperty initValue = default (TProperty ))
  301. : this(info, model, (v1, v2) =>
  302. {
  303. if (v1 == null)
  304. {
  305. if (v2 == null)
  306. {
  307. return true;
  308. }
  309. else
  310. {
  311. return false;
  312. }
  313. }
  314. else if (v2 == null)
  315. {
  316. return false;
  317. }
  318. else
  319. {
  320. return v1.Equals(v2);
  321. }
  322. }, initValue)
  323. {
  324. }
  325. /// <summary>
  326. /// <para>Create a new Value Container</para>
  327. /// <para>创建属性值容器</para>
  328. /// </summary>
  329. /// <param name="model">
  330. /// <para>The model that Value Container will be held with.</para>
  331. /// <para>所属的model实例</para>
  332. /// </param>
  333. /// <param name="info">Property name/属性名</param>
  334. /// <param name="equalityComparer">
  335. /// <para>Comparer of new/old value, for notifition.</para>
  336. /// <para>判断两个值是否相等的比较器,用于判断是否通知变更</para>
  337. /// </param>
  338. /// <param name="initValue">The first value of this container/初始值</param>
  339. public ValueContainer(string info, BindableBase model, Func<TProperty, TProperty, bool> equalityComparer, TProperty initValue = default (TProperty))
  340. {
  341. EqualityComparer = equalityComparer;
  342. PropertyName = info;
  343. PropertyType = typeof(TProperty);
  344. Model = model;
  345. Value = initValue;
  346. _Errors = new ObservableCollection<ErrorEntity>();
  347. _Errors.GetEventObservable(model)
  348. .Subscribe
  349. (
  350. e =>
  351. {
  352. model.RaiseErrorsChanged(PropertyName);
  353. }
  354. )
  355. .DisposeWith(model);
  356. }
  357. #endregion
  358. /// <summary>
  359. /// <para>Event that raised when value was changed</para>
  360. /// <para>值变更时触发的事件</para>
  361. /// </summary>
  362. public event EventHandler<ValueChangedEventArgs<TProperty>> ValueChanged;
  363. /// <summary>
  364. /// <para>Gets comparer instance of new/old value, for notifition.</para>
  365. /// <para>读取判断两个值是否相等的比较器,用于判断是否通知变更</para>
  366. /// </summary>
  367. public Func<TProperty, TProperty, bool> EqualityComparer { get; private set; }
  368. /// <summary>
  369. /// Property name /属性名
  370. /// </summary>
  371. public string PropertyName { get; private set; }
  372. TProperty _value;
  373. /// <summary>
  374. /// Value/值
  375. /// </summary>
  376. public TProperty Value
  377. {
  378. get { return _value; }
  379. set { SetValueAndTryNotify(value); }
  380. }
  381. /// <summary>
  382. /// <para>Save the value and try raise the value changed event</para>
  383. /// <para>保存值并且尝试触发更改事件</para>
  384. /// </summary>
  385. /// <param name="value">New value/属性值</param>
  386. public ValueContainer<TProperty> SetValueAndTryNotify(TProperty value)
  387. {
  388. InternalPropertyChange(this.Model, value, ref _value, PropertyName);
  389. return this;
  390. }
  391. /// <summary>
  392. /// <para>Save the value and do not try raise the value changed event</para>
  393. /// <para>仅保存值 不尝试触发更改事件</para>
  394. /// </summary>
  395. /// <param name="value">New value/属性值</param>
  396. public ValueContainer<TProperty> SetValue(TProperty value)
  397. {
  398. _value = value;
  399. return this;
  400. }
  401. private void InternalPropertyChange(BindableBase objectInstance, TProperty newValue, ref TProperty currentValue, string message)
  402. {
  403. var changing = (this.EqualityComparer != null) ?
  404. !this.EqualityComparer(newValue, currentValue) :
  405. !Object.Equals(newValue, currentValue);
  406. if (changing)
  407. {
  408. var oldvalue = currentValue;
  409. currentValue = newValue;
  410. ValueChangedEventArgs<TProperty> arg = null;
  411. Func<PropertyChangedEventArgs> lzf =
  412. () =>
  413. {
  414. arg = arg ?? new ValueChangedEventArgs<TProperty>(message, oldvalue, newValue);
  415. return arg;
  416. };
  417. objectInstance.RaisePropertyChanged(lzf);
  418. if (ValueChanged != null) ValueChanged(this, lzf() as ValueChangedEventArgs<TProperty>);
  419. }
  420. }
  421. /// <summary>
  422. /// <para>The model instance that Value Container was held.</para>
  423. /// <para>此值容器所在的Model</para>
  424. /// </summary>
  425. public BindableBase Model { get; internal set; }
  426. object IValueContainer.Value
  427. {
  428. get
  429. {
  430. return Value;
  431. }
  432. set
  433. {
  434. SetValueAndTryNotify((TProperty)value);
  435. }
  436. }
  437. /// <summary>
  438. /// Gets the type of property/读取值类型
  439. /// </summary>
  440. public Type PropertyType
  441. {
  442. get;
  443. private set;
  444. }
  445. ObservableCollection<ErrorEntity> _Errors;
  446. public ObservableCollection<ErrorEntity> Errors
  447. {
  448. get { return _Errors; }
  449. }
  450. #if NETFX_CORE
  451. bool _IsCopyToAllowed = !typeof(ICommand).GetTypeInfo().IsAssignableFrom(typeof(TProperty).GetTypeInfo());
  452. #else
  453. bool _IsCopyToAllowed = !typeof(ICommand).IsAssignableFrom(typeof(TProperty));
  454. #endif
  455. /// <summary>
  456. /// <para>Can be copied by CopyTo method</para>
  457. /// <para>是否可以被 `Copyto` 复制到另外一个属性</para>
  458. /// </summary>
  459. public bool IsCopyToAllowed
  460. {
  461. get { return _IsCopyToAllowed; }
  462. set { _IsCopyToAllowed = value; }
  463. }
  464. }
  465. /// <summary>
  466. /// <para>Event args that fired when property changed, with old value and new value field.</para>
  467. /// <para>值变化事件参数</para>
  468. /// </summary>
  469. /// <typeparam name="TProperty">Type of propery/变化属性的类型</typeparam>
  470. public class ValueChangedEventArgs<TProperty> : PropertyChangedEventArgs
  471. {
  472. /// <summary>
  473. /// Constructor of ValueChangedEventArgs
  474. /// </summary>
  475. public ValueChangedEventArgs(string propertyName, TProperty oldValue, TProperty newValue)
  476. : base(propertyName)
  477. {
  478. NewValue = newValue;
  479. OldValue = oldValue;
  480. }
  481. /// <summary>
  482. /// New Value
  483. /// </summary>
  484. public TProperty NewValue { get; private set; }
  485. /// <summary>
  486. /// Old Value
  487. /// </summary>
  488. public TProperty OldValue { get; private set; }
  489. }
  490. /// <summary>
  491. /// <para>A Bindebale Tuple</para>
  492. /// <para>一个可绑定的Tuple实现</para>
  493. /// </summary>
  494. /// <typeparam name="TItem1">Type of first item/第一个元素的类型</typeparam>
  495. /// <typeparam name="TItem2">Type of second item/第二个元素的类型</typeparam>
  496. [DataContract]
  497. public class BindableTuple<TItem1, TItem2> : BindableBase<BindableTuple<TItem1, TItem2>>
  498. {
  499. public BindableTuple(TItem1 item1, TItem2 item2)
  500. {
  501. this.IsNotificationActivated = false;
  502. Item1 = item1;
  503. Item2 = item2;
  504. this.IsNotificationActivated = true;
  505. }
  506. /// <summary>
  507. /// 第一个元素
  508. /// </summary>
  509. public TItem1 Item1
  510. {
  511. get { return _Item1Locator(this).Value; }
  512. set { _Item1Locator(this).SetValueAndTryNotify(value); }
  513. }
  514. #region Property TItem1 Item1 Setup
  515. protected Property<TItem1> _Item1 = new Property<TItem1> { LocatorFunc = _Item1Locator };
  516. static Func<BindableBase, ValueContainer<TItem1>> _Item1Locator = RegisterContainerLocator<TItem1>("Item1", model => model.Initialize("Item1", ref model._Item1, ref _Item1Locator, _Item1DefaultValueFactory));
  517. static Func<BindableBase, TItem1> _Item1DefaultValueFactory = null;
  518. #endregion
  519. /// <summary>
  520. /// 第二个元素
  521. /// </summary>
  522. public TItem2 Item2
  523. {
  524. get { return _Item2Locator(this).Value; }
  525. set { _Item2Locator(this).SetValueAndTryNotify(value); }
  526. }
  527. #region Property TItem2 Item2 Setup
  528. protected Property<TItem2> _Item2 = new Property<TItem2> { LocatorFunc = _Item2Locator };
  529. static Func<BindableBase, ValueContainer<TItem2>> _Item2Locator = RegisterContainerLocator<TItem2>("Item2", model => model.Initialize("Item2", ref model._Item2, ref _Item2Locator, _Item2DefaultValueFactory));
  530. static Func<BindableBase, TItem2> _Item2DefaultValueFactory = null;
  531. #endregion
  532. }
  533. /// <summary>
  534. /// <para>Fast create Bindable Tuple </para>
  535. /// <para>帮助快速创建BindableTuple的帮助类</para>
  536. /// </summary>
  537. public static class BindableTuple
  538. {
  539. /// <summary>
  540. /// Create a Tuple
  541. /// </summary>
  542. public static BindableTuple<TItem1, TItem2> Create<TItem1, TItem2>(TItem1 item1, TItem2 item2)
  543. {
  544. return new BindableTuple<TItem1, TItem2>(item1, item2);
  545. }
  546. }
  547. /// <summary>
  548. /// <para>Model type with detail subtype type paremeter.</para>
  549. /// <para>具有子类详细类型定义的model </para>
  550. /// <example>
  551. /// public class Class1:BindableBase&lt;Class1&gt; {}
  552. /// </example>
  553. /// </summary>
  554. /// <typeparam name="TSubClassType"> Sub Type / 子类类型</typeparam>
  555. [DataContract]
  556. public abstract class BindableBase<TSubClassType> : BindableBase, INotifyDataErrorInfo where TSubClassType : BindableBase<TSubClassType>
  557. {
  558. public BindableBase()
  559. {
  560. var meId = Interlocked.Increment(ref InstanceCount);
  561. _BindableInstanceId = string.Format("{0}:{1}", typeof(TSubClassType).Name, meId);
  562. }
  563. string _BindableInstanceId;
  564. public override string BindableInstanceId
  565. {
  566. get { return _BindableInstanceId; }
  567. }
  568. static int InstanceCount = -1;
  569. /// <summary>
  570. /// 清除值
  571. /// </summary>
  572. public void ResetPropertyValue<T>(Property<T> property)
  573. {
  574. if (property != null)
  575. {
  576. var oldContainer = property.Container;
  577. if (oldContainer != null)
  578. {
  579. property.Container = null;
  580. property.LocatorFunc(oldContainer.Model);
  581. oldContainer.SetValueAndTryNotify(property.Container.Value);
  582. property.Container = oldContainer;
  583. }
  584. }
  585. }
  586. /// <summary>
  587. /// <para>Cast a model instance to current model subtype</para>
  588. /// <para>将一个 model 引用特化为本子类型的引用</para>
  589. /// </summary>
  590. /// <param name="model"> some bindable model/某种可绑定model</param>
  591. /// <returns>Current sub type instance/本类型引用</returns>
  592. public static TSubClassType CastToCurrentType(BindableBase model)
  593. {
  594. return (TSubClassType)model;
  595. }
  596. ///// <summary>
  597. ///// <para>Type cache of container getter</para>
  598. ///// <para>每个属性类型独占的一个专门的类型缓存。</para>
  599. ///// </summary>
  600. ///// <typeparam name="TProperty"></typeparam>
  601. //protected static class TypeDic<TProperty>
  602. //{
  603. // public static Dictionary<string, Func<TSubClassType, ValueContainer<TProperty>>> _propertyContainerGetters = new Dictionary<string, Func<TSubClassType, ValueContainer<TProperty>>>();
  604. //}
  605. /// <summary>
  606. /// 根据索引获取属性值
  607. /// </summary>
  608. /// <param name="colName">属性名</param>
  609. /// <returns>属性值</returns>
  610. public override object this[string colName]
  611. {
  612. get
  613. {
  614. var lc = GetOrCreatePlainLocator(colName, this);
  615. return lc((TSubClassType)this).Value;
  616. }
  617. set
  618. {
  619. var lc = GetOrCreatePlainLocator(colName, this);
  620. lc((TSubClassType)this).Value = value;
  621. }
  622. }
  623. private static Func<TSubClassType, IValueContainer> GetOrCreatePlainLocator(string colName, BindableBase viewModel)
  624. {
  625. Func<TSubClassType, IValueContainer> pf;
  626. if (!_plainPropertyContainerGetters.TryGetValue(colName, out pf))
  627. {
  628. var p = new ValueContainer<object>(colName, viewModel);
  629. Func<TSubClassType, ValueContainer<object>> tpf = _ => p;
  630. pf = tpf;
  631. _plainPropertyContainerGetters[colName] = pf;
  632. //TypeDic<object>._propertyContainerGetters[colName] = tpf;
  633. }
  634. return pf;
  635. }
  636. #if SILVERLIGHT_5||WINDOWS_PHONE_8||WINDOWS_PHONE_7
  637. protected static Dictionary<string, Func<TSubClassType, IValueContainer>>
  638. _plainPropertyContainerGetters =
  639. new Dictionary<string, Func<TSubClassType, IValueContainer>>(StringComparer.CurrentCultureIgnoreCase);
  640. #else
  641. protected static Dictionary<string, Func<TSubClassType, IValueContainer>>
  642. _plainPropertyContainerGetters =
  643. new Dictionary<string, Func<TSubClassType, IValueContainer>>(StringComparer.CurrentCultureIgnoreCase);
  644. #endif
  645. public override string Error
  646. {
  647. get { return _ErrorLocator(this).Value; }
  648. }
  649. protected override void SetError(string value)
  650. {
  651. _ErrorLocator(this).SetValue(value);
  652. }
  653. protected override void SetErrorAndTryNotify(string value)
  654. {
  655. _ErrorLocator(this).SetValueAndTryNotify(value);
  656. }
  657. #region Property string Error Setup
  658. protected Property<string> _Error =
  659. new Property<string> { LocatorFunc = _ErrorLocator };
  660. [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
  661. static Func<BindableBase, ValueContainer<string>> _ErrorLocator =
  662. RegisterContainerLocator<string>(
  663. "Error",
  664. model =>
  665. {
  666. model._Error =
  667. model._Error
  668. ??
  669. new Property<string> { LocatorFunc = _ErrorLocator };
  670. return model._Error.Container =
  671. model._Error.Container
  672. ??
  673. new ValueContainer<string>("Error", model);
  674. });
  675. #endregion
  676. /// <summary>
  677. /// 注册一个属性容器的定位器。
  678. /// </summary>
  679. /// <typeparam name="TProperty">属性类型</typeparam>
  680. /// <param name="propertyName">属性名</param>
  681. /// <param name="getOrCreateLocatorMethod">属性定位/创建方法 也就是定位器</param>
  682. /// <returns>注册后的定位器</returns>
  683. protected static Func<BindableBase, ValueContainer<TProperty>> RegisterContainerLocator<TProperty>(string propertyName, Func<TSubClassType, ValueContainer<TProperty>> getOrCreateLocatorMethod)
  684. {
  685. //TypeDic<TProperty>._propertyContainerGetters[propertyName] = getOrCreateLocatorMethod;
  686. _plainPropertyContainerGetters[propertyName] = getOrCreateLocatorMethod;
  687. return o => getOrCreateLocatorMethod((TSubClassType)o);
  688. }
  689. /// <summary>
  690. /// 根据属性名取得一个值容器
  691. /// </summary>
  692. /// <typeparam name="TProperty">属性类型</typeparam>
  693. /// <param name="propertyName">属性名</param>
  694. /// <returns>值容器</returns>
  695. public ValueContainer<TProperty> GetValueContainer<TProperty>(string propertyName)
  696. {
  697. Func<TSubClassType, ValueContainer<TProperty>> containerGetterCreater;
  698. Func<TSubClassType, IValueContainer> contPlanGetter;
  699. if (!_plainPropertyContainerGetters.TryGetValue(propertyName, out contPlanGetter))
  700. {
  701. throw new Exception("Property Not Exists!");
  702. }
  703. containerGetterCreater = contPlanGetter as Func<TSubClassType, ValueContainer<TProperty>>;
  704. if (containerGetterCreater == null)
  705. {
  706. throw new Exception("Property '" + propertyName + "' is found but it does not match the property type '" + typeof(TProperty).Name + "'!");
  707. }
  708. return containerGetterCreater((TSubClassType)(Object)this);
  709. }
  710. /// <summary>
  711. /// 根据表达式树取得一个值容器
  712. /// </summary>
  713. /// <typeparam name="TProperty">属性类型</typeparam>
  714. /// <param name="expression">表达式树</param>
  715. /// <returns>值容器</returns>
  716. public ValueContainer<TProperty> GetValueContainer<TProperty>(Expression<Func<TSubClassType, TProperty>> expression)
  717. {
  718. var propName = MVVMSidekick.Utilities.ExpressionHelper.GetPropertyName<TSubClassType, TProperty>(expression);
  719. return GetValueContainer<TProperty>(propName);
  720. }
  721. /// <summary>
  722. /// 根据属性名取得一个值容器
  723. /// </summary>
  724. /// <param name="propertyName">属性名</param>
  725. /// <returns>值容器</returns>
  726. public IValueContainer GetValueContainer(string propertyName)
  727. {
  728. Func<TSubClassType, IValueContainer> contianerGetterCreater;
  729. if (!_plainPropertyContainerGetters.TryGetValue(propertyName, out contianerGetterCreater))
  730. {
  731. return null;
  732. }
  733. return contianerGetterCreater((TSubClassType)(Object)this);
  734. }
  735. /// <summary>
  736. /// 获取某一属性的验证错误信息
  737. /// </summary>
  738. /// <param name="propertyName">属性名</param>
  739. /// <returns>错误信息字符串</returns>
  740. protected override string GetColumnError(string propertyName)
  741. {
  742. if (_plainPropertyContainerGetters[propertyName]((TSubClassType)this).Errors.Count > 0)
  743. {
  744. var error = string.Join(",", _plainPropertyContainerGetters[propertyName]((TSubClassType)this).Errors.Select(x => x.Message));
  745. var propertyContainer = this.GetValueContainer(propertyName);
  746. #if NETFX_CORE
  747. if (propertyContainer != null && typeof(INotifyDataErrorInfo).GetTypeInfo().IsAssignableFrom(propertyContainer.PropertyType.GetTypeInfo()))
  748. #else
  749. if (propertyContainer != null && typeof(INotifyDataErrorInfo).IsAssignableFrom(propertyContainer.PropertyType))
  750. #endif
  751. {
  752. INotifyDataErrorInfo di = this[propertyName] as INotifyDataErrorInfo;
  753. if (di != null)
  754. {
  755. error = error + "\r\n-----Inner " + propertyName + " as INotifyDataErrorInfo -------\r\n\t" + di.HasErrors.ToString();
  756. }
  757. }
  758. return error;
  759. }
  760. return null;
  761. }
  762. /// <summary>
  763. /// 获取所有属性名,包括静态声明和动态添加的
  764. /// </summary>
  765. /// <returns></returns>
  766. public override string[] GetFieldNames()
  767. {
  768. return _plainPropertyContainerGetters.Keys.ToArray();
  769. }
  770. /// <summary>
  771. /// 创建一个VM副本
  772. /// </summary>
  773. /// <returns>新引用</returns>
  774. public TSubClassType Clone()
  775. {
  776. var x = (TSubClassType)Activator.CreateInstance(typeof(TSubClassType));
  777. CopyTo(x);
  778. return x;
  779. }
  780. static void Copyref<T>(T source, ref T target)
  781. {
  782. if (source == null)
  783. {
  784. target = source;
  785. return;
  786. }
  787. var sourcetype = source.GetType().GetTypeOrTypeInfo();
  788. if (sourcetype.IsValueType || source is string)
  789. {
  790. target = source;
  791. }
  792. #if ! (SILVERLIGHT_5 || WINDOWS_PHONE_8|| WINDOWS_PHONE_7 || NETFX_CORE)
  793. else if (typeof(ICloneable).IsAssignableFrom(sourcetype))
  794. {
  795. target = (T)((ICloneable)source).Clone();
  796. }
  797. #endif
  798. else if (typeof(System.Collections.IList).GetTypeOrTypeInfo().IsAssignableFrom(sourcetype))
  799. {
  800. var tarcol = target as System.Collections.IList;
  801. var scol = source as System.Collections.IList;
  802. if (tarcol == null)
  803. {
  804. var newcol = sourcetype.IsArray ?
  805. Array.CreateInstance(sourcetype.GetElementType(), scol.Count) :
  806. System.Activator.CreateInstance(source.GetType(), new object[0]) as System.Collections.IList;
  807. tarcol = (System.Collections.IList)newcol;
  808. }
  809. else
  810. {
  811. tarcol.Clear();
  812. }
  813. if (tarcol != null)
  814. {
  815. foreach (var item in scol)
  816. {
  817. object newv = null;
  818. Copyref(item, ref newv);
  819. tarcol.Add(newv);
  820. }
  821. target = (T)tarcol;
  822. }
  823. else
  824. {
  825. target = default(T);
  826. }
  827. }
  828. }
  829. public void CopyTo(TSubClassType target)
  830. {
  831. foreach (var item in GetFieldNames())
  832. {
  833. var ctThis = GetValueContainer(item);
  834. var ctTarget = target.GetValueContainer(item);
  835. if (ctThis.IsCopyToAllowed)
  836. {
  837. object temp = null;
  838. Copyref(this[item], ref temp);
  839. target[item] = temp;
  840. }
  841. }
  842. }
  843. public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged
  844. {
  845. add { _ErrorsChanged += value; }
  846. remove { _ErrorsChanged -= value; }
  847. }
  848. public System.Collections.IEnumerable GetErrors(string propertyName)
  849. {
  850. if (this.GetFieldNames().Contains(propertyName))
  851. {
  852. return this.GetValueContainer(propertyName).Errors;
  853. }
  854. else
  855. {
  856. return null;
  857. }
  858. }
  859. public bool HasErrors
  860. {
  861. get
  862. {
  863. // return false;
  864. RefreshErrors();
  865. return !string.IsNullOrEmpty(this.Error);
  866. }
  867. }
  868. private void RefreshErrors()
  869. {
  870. var sb = new StringBuilder();
  871. var rt = GetAllErrors().Select(x =>
  872. {
  873. return sb.Append(x.Message).Append(":").AppendLine(x.Exception == null ? " " : x.Exception.ToString());
  874. }
  875. )
  876. .ToArray();
  877. this.SetErrorAndTryNotify(sb.ToString());
  878. }
  879. public ErrorEntity[] GetAllErrors()
  880. {
  881. var errors = GetFieldNames()
  882. .SelectMany(name => this.GetValueContainer(name).Errors)
  883. .Where(x => x != null)
  884. .ToArray();
  885. return errors;
  886. }
  887. //public override IDictionary<string,object > Values
  888. //{
  889. // get { return new BindableAccesser<TSubClassType>(this); }
  890. //}
  891. /// <summary>
  892. /// 给这个模型分配的消息路由引用(延迟加载)
  893. /// </summary>
  894. public override EventRouter EventRouter
  895. {
  896. get { return _EventRouterLocator(this).Value; }
  897. set { _EventRouterLocator(this).SetValueAndTryNotify(value); }
  898. }
  899. #region Property EventRouter EventRouter Setup
  900. protected Property<EventRouter> _EventRouter = new Property<EventRouter> { LocatorFunc = _EventRouterLocator };
  901. static Func<BindableBase, ValueContainer<EventRouter>> _EventRouterLocator = RegisterContainerLocator<EventRouter>("EventRouter", model => model.Initialize("EventRouter", ref model._EventRouter, ref _EventRouterLocator, _EventRouterDefaultValueFactory));
  902. static Func<EventRouter> _EventRouterDefaultValueFactory = () => { return new EventRouter(); };
  903. #endregion
  904. }
  905. public interface IDisposeGroup : IDisposable
  906. {
  907. /// <summary>
  908. /// 增加一个一起Dispose的对象
  909. /// </summary>
  910. /// <param name="item"></param>
  911. /// <param name="comment"></param>
  912. /// <param name="member"></param>
  913. /// <param name="file"></param>
  914. /// <param name="line"></param>
  915. void AddDisposable(IDisposable item, string comment = "", string member = "", string file = "", int line = -1);
  916. /// <summary>
  917. /// 增加一个Dispose的时候需要做的操作
  918. /// </summary>
  919. /// <param name="action"></param>
  920. /// <param name="comment"></param>
  921. /// <param name="member"></param>
  922. /// <param name="file"></param>
  923. /// <param name="line"></param>
  924. void AddDisposeAction(Action action, string comment = "", string member = "", string file = "", int line = -1);
  925. IList<DisposeEntry> DisposeInfoList { get; }
  926. event EventHandler<DisposeEventArgs> DisposingEntry;
  927. event EventHandler<DisposeEventArgs> DisposedEntry;
  928. }
  929. public class DisposeEventArgs : EventArgs
  930. {
  931. public static DisposeEventArgs Create(DisposeEntry info)
  932. {
  933. return new DisposeEventArgs(info);
  934. }
  935. public DisposeEventArgs(DisposeEntry info)
  936. {
  937. DisposeEntry = info;
  938. }
  939. public DisposeEntry DisposeEntry { get; private set; }
  940. }
  941. [DataContract]
  942. public abstract class DisposeGroupBase : IDisposeGroup
  943. {
  944. public DisposeGroupBase()
  945. {
  946. CreateDisposeList();
  947. }
  948. private void CreateDisposeList()
  949. {
  950. _disposeInfoList = new Lazy<List<DisposeEntry>>(() => new List<DisposeEntry>(), true);
  951. }
  952. [OnDeserializing]
  953. public void OnDeserializing(System.Runtime.Serialization.StreamingContext context)
  954. {
  955. OnDeserializingActions();
  956. }
  957. protected virtual void OnDeserializingActions()
  958. {
  959. CreateDisposeList();
  960. }
  961. #region Disposing Logic/Disposing相关逻辑
  962. ~DisposeGroupBase()
  963. {
  964. Dispose(false);
  965. }
  966. /// <summary>
  967. /// <para>Logic actions need to be executed when the instance is disposing</para>
  968. /// <para>销毁对象时 需要执行的操作</para>
  969. /// </summary>
  970. private Lazy<List<DisposeEntry>> _disposeInfoList;
  971. public IList<DisposeEntry> DisposeInfoList { get { return _disposeInfoList.Value; } }
  972. //protected static Func<DisposeGroupBase, List<DisposeInfo>> _locateDisposeInfos =
  973. // m =>
  974. // {
  975. // if (m._disposeInfoList == null)
  976. // {
  977. // Interlocked.CompareExchange(ref m._disposeInfoList, new List<DisposeInfo>(), null);
  978. // }
  979. // return m._disposeInfoList;
  980. // };
  981. /// <summary>
  982. /// <para>Register logic actions need to be executed when the instance is disposing</para>
  983. /// <para>注册一个销毁对象时需要执行的操作</para>
  984. /// </summary>
  985. /// <param name="newAction">Disposing action/销毁操作</param>
  986. public void AddDisposeAction(Action newAction, string comment = "", [CallerMemberName] string caller = "", [CallerFilePath] string file = "", [CallerLineNumber]int line = -1)
  987. {
  988. var di = new DisposeEntry
  989. {
  990. CallingCodeContext = CallingCodeContext.Create(comment, caller, file, line),
  991. Action = newAction
  992. };
  993. _disposeInfoList.Value.Add(di);
  994. }
  995. /// <summary>
  996. /// <para>Register an object that need to be disposed when the instance is disposing</para>
  997. /// <para>销毁对象时 需要一起销毁的对象</para>
  998. /// </summary>
  999. /// <param name="item">disposable object/需要一起销毁的对象</param>
  1000. public void AddDisposable(IDisposable item, string comment = "", [CallerMemberName] string caller = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = -1)
  1001. {
  1002. AddDisposeAction(() => item.Dispose(), comment, caller, file, line);
  1003. }
  1004. public void Dispose()
  1005. {
  1006. Dispose(true);
  1007. GC.SuppressFinalize(this);
  1008. }
  1009. /// <summary>
  1010. /// <para>Do all the dispose </para>
  1011. /// <para>销毁,尝试运行所有注册的销毁操作</para>
  1012. /// </summary>
  1013. protected virtual void Dispose(bool disposing)
  1014. {
  1015. var disposeList = Interlocked.Exchange(ref _disposeInfoList, new Lazy<List<DisposeEntry>>(() => new List<DisposeEntry>(), true));
  1016. if (disposeList != null)
  1017. {
  1018. var l = disposeList.Value
  1019. .Select
  1020. (
  1021. info =>
  1022. {
  1023. var ea = DisposeEventArgs.Create(info);
  1024. //Exception gotex = null;
  1025. try
  1026. {
  1027. if (DisposingEntry != null)
  1028. {
  1029. DisposingEntry(this, ea);
  1030. }
  1031. info.Action();
  1032. }
  1033. catch (Exception ex)
  1034. {
  1035. info.Exception = ex;
  1036. }
  1037. finally
  1038. {
  1039. if (DisposedEntry != null)
  1040. {
  1041. DisposedEntry(this, ea);
  1042. }
  1043. }
  1044. return info;
  1045. }
  1046. )
  1047. .Where(x => x.Exception != null)
  1048. .ToArray();
  1049. if (l.Length > 0)
  1050. {
  1051. OnDisposeExceptions(l);
  1052. }
  1053. }
  1054. _disposeInfoList = null;
  1055. if (disposing)
  1056. {
  1057. }
  1058. }
  1059. /// <summary>
  1060. /// <para>If dispose actions got exceptions, will handled here. </para>
  1061. /// <para>处理Dispose 时产生的Exception</para>
  1062. /// </summary>
  1063. /// <param name="disposeInfoWithExceptions">
  1064. /// <para>The exception and dispose infomation</para>
  1065. /// <para>需要处理的异常信息</para>
  1066. /// </param>
  1067. protected virtual void OnDisposeExceptions(IList<DisposeEntry> disposeInfoWithExceptions)
  1068. {
  1069. }
  1070. #endregion
  1071. public event EventHandler<DisposeEventArgs> DisposingEntry;
  1072. public event EventHandler<DisposeEventArgs> DisposedEntry;
  1073. }
  1074. /// <summary>
  1075. /// <para>Dispose action infomation struct</para>
  1076. /// <para>注册销毁方法时的相关信息</para>
  1077. /// </summary>
  1078. public struct DisposeEntry
  1079. {
  1080. /// <summary>
  1081. /// <para>Code Context in this dispose action execution register .</para>
  1082. /// <para>执行代码上下文</para>
  1083. /// </summary>
  1084. public CallingCodeContext CallingCodeContext { get; set; }
  1085. /// <summary>
  1086. /// <para>Exception thrown in this dispose action execution .</para>
  1087. /// <para>执行此次Dispose动作产生的Exception</para>
  1088. /// </summary>
  1089. public Exception Exception { get; set; }
  1090. /// <summary>
  1091. /// <para>Dispose action.</para>
  1092. /// <para>Dispose动作</para>
  1093. /// </summary>
  1094. public Action Action { get; set; }
  1095. }
  1096. public interface IBindable : INotifyPropertyChanged, IDisposable, IDisposeGroup
  1097. {
  1098. EventRouter EventRouter { get; set; }
  1099. string BindableInstanceId { get; }
  1100. string Error { get; }
  1101. //IDictionary<string,object > Values { get; }
  1102. string[] GetFieldNames();
  1103. object this[string name] { get; set; }
  1104. }
  1105. //#if !NETFX_CORE
  1106. // public class StringToViewModelInstanceConverter : TypeConverter
  1107. // {
  1108. // public override bool CanConvertTo(ITypeDescriptorContext context, Type sourceType)
  1109. // {
  1110. // //if (sourceType == typeof(string))
  1111. // return true;
  1112. // //return base.CanConvertFrom(context, sourceType);
  1113. // }
  1114. // public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
  1115. // {
  1116. // return true;
  1117. // }
  1118. // public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
  1119. // {
  1120. // var str = value.ToString();
  1121. // var t = Type.GetType(str);
  1122. // var v = Activator.CreateInstance(t);
  1123. // return v;
  1124. // //// return base.ConvertFrom(context, culture, value);
  1125. // }
  1126. // public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
  1127. // {
  1128. // return value.ToString();
  1129. // }
  1130. // }
  1131. // [TypeConverter(typeof(StringToViewModelInstanceConverter))]
  1132. //#endif
  1133. public interface IViewModelLifetime
  1134. {
  1135. Task OnBindedToView(MVVMSidekick.Views.IView view, IViewModel oldValue);
  1136. Task OnUnbindedFromView(MVVMSidekick.Views.IView view, IViewModel newValue);
  1137. Task OnBindedViewLoad(MVVMSidekick.Views.IView view);
  1138. Task OnBindedViewUnload(MVVMSidekick.Views.IView view);
  1139. }
  1140. public partial interface IViewModel : IBindable, INotifyPropertyChanged, IViewModelLifetime
  1141. {
  1142. #if NETFX_CORE
  1143. Windows.UI.Core.CoreDispatcher Dispatcher { get; }
  1144. #else
  1145. Dispatcher Dispatcher { get; }
  1146. #endif
  1147. Task WaitForClose(Action closingCallback = null);
  1148. bool IsUIBusy { get; }
  1149. bool HaveReturnValue { get; }
  1150. void Close();
  1151. MVVMSidekick.Views.StageManager StageManager { get; set; }
  1152. Task<Tout> ExecuteTask<Tin, Tout>(Func<Tin, CancellationToken, Task<Tout>> taskBody, Tin inputContext, CancellationToken cancellationToken, bool UIBusyWhenExecuting = true);
  1153. Task ExecuteTask<Tin>(Func<Tin, CancellationToken, Task> taskBody, Tin inputContext, CancellationToken cancellationToken, bool UIBusyWhenExecuting = true);
  1154. Task<Tout> ExecuteTask<Tin, Tout>(Func<Tin, Task<Tout>> taskBody, Tin inputContext, bool UIBusyWhenExecuting = true);
  1155. Task ExecuteTask<Tin>(Func<Tin, Task> taskBody, Tin inputContext, bool UIBusyWhenExecuting = true);
  1156. Task<Tout> ExecuteTask<Tout>(Func<Task<Tout>> taskBody, bool UIBusyWhenExecuting = true);
  1157. Task ExecuteTask(Func<Task> taskBody, bool UIBusyWhenExecuting = true);
  1158. //IObservable<Task<Tout>> DoExecuteUIBusyTask<Tin, Tout>(this IObservable<Tin> sequence,IViewModel , Func<Tin, Task<Tout>> taskBody);
  1159. //IObservable<Task<Tout>> DoExecuteUIBusyTask<Tin, Tout>(this IObservable<Tin> sequence, Func<Tin,Task<Tout>> taskBody, TaskScheduler scheduler);
  1160. /// <summary>
  1161. /// Set: Will VM be Disposed when unbind from View.
  1162. /// </summary>
  1163. bool IsDisposingWhenUnbindRequired { get; }
  1164. /// <summary>
  1165. /// Set: Will VM be Disposed when unload from View.
  1166. /// </summary>
  1167. bool IsDisposingWhenUnloadRequired { get; }
  1168. #if NETFX_CORE
  1169. void LoadState(Object navigationParameter, Dictionary<String, Object> pageState);
  1170. void SaveState(Dictionary<String, Object> pageState);
  1171. #endif
  1172. }
  1173. public partial interface IViewModel<TResult> : IViewModel
  1174. {
  1175. Task<TResult> WaitForCloseWithResult(Action closingCallback = null);
  1176. TResult Result { get; set; }
  1177. }
  1178. [DataContract]
  1179. public struct NoResult
  1180. {
  1181. }
  1182. public struct ShowAwaitableResult<TViewModel>
  1183. {
  1184. public TViewModel ViewModel { get; set; }
  1185. public Task Closing { get; set; }
  1186. }
  1187. public partial class ViewModelBase<TViewModel, TResult> : ViewModelBase<TViewModel>, IViewModel<TResult>
  1188. where TViewModel : ViewModelBase<TViewModel, TResult>, IViewModel<TResult>
  1189. {
  1190. protected override void Dispose(bool disposing)
  1191. {
  1192. base.Dispose(disposing);
  1193. }
  1194. public override bool HaveReturnValue { get { return true; } }
  1195. public async Task<TResult> WaitForCloseWithResult(Action closingCallback = null)
  1196. {
  1197. var t = new TaskCompletionSource<TResult>();
  1198. this.AddDisposeAction(
  1199. () =>
  1200. {
  1201. if (closingCallback != null)
  1202. {
  1203. closingCallback();
  1204. }
  1205. t.SetResult(Result);
  1206. }
  1207. );
  1208. await t.Task;
  1209. return Result;
  1210. }
  1211. public TResult Result
  1212. {
  1213. get { return _ResultLocator(this).Value; }
  1214. set { _ResultLocator(this).SetValueAndTryNotify(value); }
  1215. }
  1216. #region Property TResult Result Setup
  1217. protected Property<TResult> _Result =
  1218. new Property<TResult> { LocatorFunc = _ResultLocator };
  1219. [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
  1220. static Func<BindableBase, ValueContainer<TResult>> _ResultLocator =
  1221. RegisterContainerLocator<TResult>(
  1222. "Result",
  1223. model =>
  1224. {
  1225. model._Result =
  1226. model._Result
  1227. ??
  1228. new Property<TResult> { LocatorFunc = _ResultLocator };
  1229. return model._Result.Container =
  1230. model._Result.Container
  1231. ??
  1232. new ValueContainer<TResult>("Result", model);
  1233. });
  1234. #endregion
  1235. }
  1236. /// <summary>
  1237. /// 一个VM,带有若干界面特性
  1238. /// </summary>
  1239. /// <typeparam name="TViewModel">本身的类型</typeparam>
  1240. public abstract partial class ViewModelBase<TViewModel> : BindableBase<TViewModel>, IViewModel where TViewModel : ViewModelBase<TViewModel>
  1241. {
  1242. protected override void Dispose(bool disposing)
  1243. {
  1244. base.Dispose(disposing);
  1245. }
  1246. public ViewModelBase()
  1247. {
  1248. #if WPF
  1249. this.IsDisposingWhenUnloadRequired = true;
  1250. #endif
  1251. GetValueContainer(x => x.UIBusyTaskCount)
  1252. .GetNewValueObservable()
  1253. .Select(e =>
  1254. e.EventArgs != 0)
  1255. .DistinctUntilChanged()
  1256. .Subscribe(isBusy =>
  1257. IsUIBusy = isBusy)
  1258. .DisposeWith(this);
  1259. }
  1260. Task IViewModelLifetime.OnBindedToView(IView view, IViewModel oldValue)
  1261. {
  1262. return OnBindedToView(view, oldValue);
  1263. }
  1264. Task IViewModelLifetime.OnUnbindedFromView(IView view, IViewModel newValue)
  1265. {
  1266. return OnUnbindedFromView(view, newValue);
  1267. }
  1268. Task IViewModelLifetime.OnBindedViewLoad(IView view)
  1269. {
  1270. foreach (var item in GetFieldNames())
  1271. {
  1272. RaisePropertyChanged(() => new PropertyChangedEventArgs(item));
  1273. }
  1274. return OnBindedViewLoad(view);
  1275. }
  1276. Task IViewModelLifetime.OnBindedViewUnload(IView view)
  1277. {
  1278. return OnBindedViewUnload(view);
  1279. }
  1280. /// <summary>
  1281. /// This will be invoked by view when this viewmodel is set to view's ViewModel property.
  1282. /// </summary>
  1283. /// <param name="view">Set target view</param>
  1284. /// <param name="oldValue">Value before set.</param>
  1285. /// <returns>Task awaiter</returns>
  1286. protected virtual async Task OnBindedToView(MVVMSidekick.Views.IView view, IViewModel oldValue)
  1287. {
  1288. //#if SILVERLIGHT_5
  1289. // await T.askEx.Yield();
  1290. //#else
  1291. // await T.ask.Yield();
  1292. //#endif
  1293. StageManager = new StageManager(this) { CurrentBindingView = view };
  1294. StageManager.InitParent(() => view.Parent);
  1295. //StageManager.DisposeWith(this);
  1296. await TaskExHelper.Yield();
  1297. }
  1298. /// <summary>
  1299. /// This will be invoked by view when this instance of viewmodel in ViewModel property is overwritten.
  1300. /// </summary>
  1301. /// <param name="view">Overwrite target view.</param>
  1302. /// <param name="newValue">The value replacing </param>
  1303. /// <returns>Task awaiter</returns>
  1304. protected virtual async Task OnUnbindedFromView(MVVMSidekick.Views.IView view, IViewModel newValue)
  1305. {
  1306. if (IsDisposingWhenUnbindRequired)
  1307. {
  1308. Dispose();
  1309. }
  1310. await TaskExHelper.Yield();
  1311. }
  1312. /// <summary>
  1313. /// This will be invoked by view when the view fires Load event and this viewmodel instance is already in view's ViewModel property
  1314. /// </summary>
  1315. /// <param name="view">View that firing Load event</param>
  1316. /// <returns>Task awaiter</returns>
  1317. protected virtual async Task OnBindedViewLoad(IView view)
  1318. {
  1319. StageManager = new StageManager(this) { CurrentBindingView = view };
  1320. StageManager.InitParent(() => view.Parent);
  1321. //StageManager.DisposeWith(this);
  1322. await TaskExHelper.Yield();
  1323. }
  1324. /// <summary>
  1325. /// This will be invoked by view when the view fires Unload event and this viewmodel instance is still in view's ViewModel property
  1326. /// </summary>
  1327. /// <param name="view">View that firing Unload event</param>
  1328. /// <returns>Task awaiter</returns>
  1329. protected virtual async Task OnBindedViewUnload(IView view)
  1330. {
  1331. if (IsDisposingWhenUnloadRequired)
  1332. {
  1333. this.Dispose();
  1334. }
  1335. await TaskExHelper.Yield();
  1336. }
  1337. /// <summary>
  1338. /// Set: Will VM be Disposed when unbind from View.
  1339. /// </summary>
  1340. public bool IsDisposingWhenUnbindRequired { get; protected set; }
  1341. /// <summary>
  1342. /// Set: Will VM be Disposed when unload from View.
  1343. /// </summary>
  1344. public bool IsDisposingWhenUnloadRequired { get; protected set; }
  1345. #if NETFX_CORE
  1346. /// <summary>
  1347. /// Populates the page with content passed during navigation. Any saved state is also
  1348. /// provided when recreating a page from a prior session.
  1349. /// </summary>
  1350. /// <param name="navigationParameter">The parameter value passed to
  1351. /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
  1352. /// </param>
  1353. /// <param name="pageState">A dictionary of state preserved by this page during an earlier
  1354. /// session. This will be null the first time a page is visited.</param>
  1355. public virtual void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
  1356. {
  1357. }
  1358. /// <summary>
  1359. /// Preserves state associated with this page in case the application is suspended or the
  1360. /// page is discarded from the navigation cache. Values must conform to the serialization
  1361. /// requirements of <see cref="SuspensionManager.SessionState"/>.
  1362. /// </summary>
  1363. /// <param name="pageState">An empty dictionary to be populated with serializable state.</param>
  1364. public virtual void SaveState(Dictionary<String, Object> pageState)
  1365. {
  1366. }
  1367. #endif
  1368. MVVMSidekick.Views.StageManager _StageManager;
  1369. public MVVMSidekick.Views.StageManager StageManager
  1370. {
  1371. get { return _StageManager; }
  1372. set { _StageManager = value; }
  1373. }
  1374. /// <summary>
  1375. /// 是否有返回值
  1376. /// </summary>
  1377. public virtual boo

Large files files are truncated, but you can click here to view the full file