PageRenderTime 51ms CodeModel.GetById 3ms app.highlight 35ms 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

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

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