PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/MVVMSidekick/MVVMSidekick.Shared/Patterns.cs

https://github.com/zoujuny/MVVM-Sidekick
C# | 700 lines | 480 code | 206 blank | 14 comment | 19 complexity | 25e193e81abeb8d415b53643c93ff90b MD5 | raw 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.ViewModels;
  13. using MVVMSidekick.Commands;
  14. using System.Runtime.CompilerServices;
  15. using MVVMSidekick.Reactive;
  16. using System.Reactive.Linq;
  17. using System.Reactive.Subjects;
  18. using System.Reactive;
  19. using MVVMSidekick.EventRouting;
  20. using System.Collections.ObjectModel;
  21. using System.Collections.Specialized;
  22. using System.IO;
  23. using System.Collections;
  24. using System.Diagnostics;
  25. using MVVMSidekick.Utilities;
  26. using System.Windows;
  27. #if NETFX_CORE
  28. using Windows.UI.Xaml;
  29. using Windows.UI.Xaml.Data;
  30. using Windows.UI.Xaml.Controls;
  31. using System.Collections.Concurrent;
  32. using Windows.UI.Xaml.Navigation;
  33. using Windows.UI.Xaml.Controls.Primitives;
  34. #elif WPF
  35. using System.Windows.Controls;
  36. using System.Windows.Data;
  37. using System.Collections.Concurrent;
  38. using System.Windows.Navigation;
  39. using MVVMSidekick.Views;
  40. using System.Windows.Controls.Primitives;
  41. #elif SILVERLIGHT_5||SILVERLIGHT_4
  42. using System.Windows;
  43. using System.Windows.Controls;
  44. using System.Windows.Data;
  45. using System.Windows.Navigation;
  46. using System.Windows.Controls.Primitives;
  47. #elif WINDOWS_PHONE_8||WINDOWS_PHONE_7
  48. using System.Windows;
  49. using System.Windows.Controls;
  50. using Microsoft.Phone.Controls;
  51. using System.Windows.Data;
  52. using System.Windows.Navigation;
  53. using System.Windows.Controls;
  54. using System.Windows.Data;
  55. using System.Windows.Controls.Primitives;
  56. #endif
  57. namespace MVVMSidekick
  58. {
  59. namespace Patterns
  60. {
  61. public class ElementBinderBase<TSubType> : DependencyObject, IDisposable where
  62. TSubType : ElementBinderBase<TSubType>
  63. {
  64. public ElementBinderBase() { }
  65. public ElementBinderBase(Action<TSubType> bindingAction, Action<TSubType> disposeAction)
  66. {
  67. _bindingAction = bindingAction;
  68. _disposeAction = ts =>
  69. {
  70. disposeAction(ts);
  71. };
  72. }
  73. protected Action<TSubType> _bindingAction;
  74. protected Action<TSubType> _disposeAction;
  75. protected static PropertyChangedCallback BinderPropertyChangedCallback = (o, e) =>
  76. {
  77. if (e.NewValue is TSubType)
  78. {
  79. var eb = e.NewValue as TSubType;
  80. eb.Element = o as FrameworkElement;
  81. if (eb._bindingAction != null)
  82. {
  83. try
  84. {
  85. eb._bindingAction(eb);
  86. }
  87. catch (Exception ex)
  88. {
  89. Debug.WriteLine(ex);
  90. }
  91. finally
  92. {
  93. eb._bindingAction = null;
  94. }
  95. }
  96. }
  97. };
  98. public FrameworkElement Element
  99. {
  100. get { return (FrameworkElement)GetValue(ElementProperty); }
  101. set { SetValue(ElementProperty, value); }
  102. }
  103. // Using a DependencyProperty as the backing store for Element. This enables animation, styling, binding, etc...
  104. public static readonly DependencyProperty ElementProperty =
  105. DependencyProperty.Register("Element", typeof(FrameworkElement), typeof(TSubType), new PropertyMetadata(null));
  106. #region IDisposable Members
  107. int _Disposed = 0;
  108. ~ElementBinderBase()
  109. {
  110. Dispose(false);
  111. }
  112. public void Dispose()
  113. {
  114. Dispose(true);
  115. GC.SuppressFinalize(this);
  116. }
  117. virtual protected void Dispose(bool disposing)
  118. {
  119. var v = Interlocked.Exchange(ref _Disposed, 1);
  120. if (v == 0)
  121. {
  122. try
  123. {
  124. if (_disposeAction != null)
  125. {
  126. _disposeAction(this as TSubType);
  127. }
  128. }
  129. catch (Exception ex)
  130. {
  131. Debug.WriteLine(ex);
  132. }
  133. finally
  134. {
  135. _disposeAction = null;
  136. }
  137. _disposeAction = null;
  138. _bindingAction = null;
  139. }
  140. }
  141. #endregion
  142. }
  143. namespace ItemsAndSelection
  144. {
  145. public class ItemsAndSelectionGroup<T> : ItemsAndSelectionGroup<T, ObservableCollection<T>, SelectionMode>
  146. {
  147. static ItemsAndSelectionGroup()
  148. {
  149. _ItemsDefaultValueFactory = () => new ObservableCollection<T>();
  150. }
  151. }
  152. public class ItemsAndSelectionGroupBinder : ElementBinderBase<ItemsAndSelectionGroupBinder>
  153. {
  154. public ItemsAndSelectionGroupBinder(Action<ItemsAndSelectionGroupBinder> bindingAction, Action<ItemsAndSelectionGroupBinder> disposeAction)
  155. : base(bindingAction, disposeAction)
  156. { }
  157. public static ItemsAndSelectionGroupBinder GetBinder(DependencyObject obj)
  158. {
  159. return (ItemsAndSelectionGroupBinder)obj.GetValue(BinderProperty);
  160. }
  161. public static void SetBinder(DependencyObject obj, ItemsAndSelectionGroupBinder value)
  162. {
  163. obj.SetValue(BinderProperty, value);
  164. }
  165. // Using a DependencyProperty as the backing store for ElementBinder. This enables animation, styling, binding, etc...
  166. public static readonly DependencyProperty BinderProperty =
  167. DependencyProperty.RegisterAttached("Binder", typeof(ItemsAndSelectionGroupBinder), typeof(ItemsAndSelectionGroupBinder), new PropertyMetadata(
  168. null,
  169. BinderPropertyChangedCallback));
  170. }
  171. public interface IItemsAndSelectionGroupBinding
  172. {
  173. MVVMSidekick.Patterns.ItemsAndSelection.ItemsAndSelectionGroupBinder Binder { get; set; }
  174. }
  175. public class ItemsAndSelectionGroup<T, TCollection, TSelectionMode> : BindableBase<ItemsAndSelectionGroup<T, TCollection, TSelectionMode>>, IItemsAndSelectionGroupBinding
  176. where TCollection : ICollection<T>, INotifyCollectionChanged
  177. {
  178. public ItemsAndSelectionGroup()
  179. {
  180. base.AddDisposeAction(() => Binder = null);
  181. this.GetValueContainer(x => x.Items).GetNullObservable()
  182. .Subscribe(_ => ResetSelection())
  183. .DisposeWith(this);
  184. }
  185. private void ResetSelection()
  186. {
  187. ResetPropertyValue(_SelectedValue);
  188. ResetPropertyValue(_SelectedIndex);
  189. ResetPropertyValue(_SelectedItem);
  190. }
  191. public ItemsAndSelectionGroupBinder Binder
  192. {
  193. get { return _BinderLocator(this).Value; }
  194. set { _BinderLocator(this).SetValueAndTryNotify(value); }
  195. }
  196. #region Property ElementBinder Binder Setup
  197. protected Property<ItemsAndSelectionGroupBinder> _Binder = new Property<ItemsAndSelectionGroupBinder> { LocatorFunc = _BinderLocator };
  198. static Func<BindableBase, ValueContainer<ItemsAndSelectionGroupBinder>> _BinderLocator = RegisterContainerLocator<ItemsAndSelectionGroupBinder>("Binder", model => model.Initialize("Binder", ref model._Binder, ref _BinderLocator, _BinderDefaultValueFactory));
  199. static Func<BindableBase, ItemsAndSelectionGroupBinder> _BinderDefaultValueFactory = model =>
  200. {
  201. var vm = CastToCurrentType(model);
  202. Action<ItemsAndSelectionGroupBinder> bindingAc =
  203. eb =>
  204. {
  205. var ls = eb.Element as ItemsControl;
  206. if (ls == null)
  207. {
  208. return;
  209. }
  210. if (vm == null)
  211. {
  212. return;
  213. }
  214. var itemsBinding = new Binding()
  215. {
  216. Source = vm,
  217. Mode = BindingMode.OneWay,
  218. Path = new PropertyPath("Items")
  219. };
  220. BindingOperations.SetBinding(ls, ItemsControl.ItemsSourceProperty, itemsBinding);
  221. if (!(ls is Selector))
  222. {
  223. return;
  224. }
  225. var selectedBinding = new Binding()
  226. {
  227. Source = vm,
  228. Mode = BindingMode.TwoWay,
  229. Path = new PropertyPath("SelectedItem")
  230. };
  231. BindingOperations.SetBinding(ls, Selector.SelectedItemProperty, selectedBinding);
  232. var selectedindexBinding = new Binding()
  233. {
  234. Source = vm,
  235. Mode = BindingMode.TwoWay,
  236. Path = new PropertyPath("SelectedIndex")
  237. };
  238. BindingOperations.SetBinding(ls, Selector.SelectedIndexProperty, selectedindexBinding);
  239. var selectedValuePathBinding = new Binding()
  240. {
  241. Source = vm,
  242. Mode = BindingMode.TwoWay,
  243. Path = new PropertyPath("SelectedValuePath")
  244. };
  245. BindingOperations.SetBinding(ls, Selector.SelectedValuePathProperty, selectedValuePathBinding);
  246. var selectedValueBinding = new Binding()
  247. {
  248. Source = vm,
  249. Mode = BindingMode.TwoWay,
  250. Path = new PropertyPath("SelectedValue")
  251. };
  252. BindingOperations.SetBinding(ls, Selector.SelectedValueProperty, selectedValueBinding);
  253. #if SILVERLIGHT_5 || WINDOWS_PHONE_8||WINDOWS_PHONE_7
  254. if (!(ls is ListBox))
  255. #else
  256. if (!(ls is ListBox) && (!(ls is ListView)))
  257. #endif
  258. {
  259. return;
  260. }
  261. var selectionModeBinding = new Binding()
  262. {
  263. Source = vm,
  264. Mode = BindingMode.TwoWay,
  265. Path = new PropertyPath("SelectionMode")
  266. };
  267. BindingOperations.SetBinding(ls, ListBox.SelectionModeProperty, selectionModeBinding);
  268. };
  269. return new ItemsAndSelectionGroupBinder(bindingAc, (e) => e.Element = null).DisposeWith(vm);
  270. };
  271. #endregion
  272. public FrameworkElement BindedTo
  273. {
  274. get { return Binder.Element; }
  275. }
  276. public TSelectionMode SelectionMode
  277. {
  278. get { return _SelectionModeLocator(this).Value; }
  279. set { _SelectionModeLocator(this).SetValueAndTryNotify(value); }
  280. }
  281. #region Property TSelectionMode SelectionMode Setup
  282. protected Property<TSelectionMode> _SelectionMode = new Property<TSelectionMode> { LocatorFunc = _SelectionModeLocator };
  283. static Func<BindableBase, ValueContainer<TSelectionMode>> _SelectionModeLocator = RegisterContainerLocator<TSelectionMode>("SelectionMode", model => model.Initialize("SelectionMode", ref model._SelectionMode, ref _SelectionModeLocator, _SelectionModeDefaultValueFactory));
  284. static Func<TSelectionMode> _SelectionModeDefaultValueFactory = null;
  285. #endregion
  286. public string SelectedValuePath
  287. {
  288. get { return _SelectedValuePathLocator(this).Value; }
  289. set { _SelectedValuePathLocator(this).SetValueAndTryNotify(value); }
  290. }
  291. #region Property string SelectedValuePath Setup
  292. protected Property<string> _SelectedValuePath = new Property<string> { LocatorFunc = _SelectedValuePathLocator };
  293. static Func<BindableBase, ValueContainer<string>> _SelectedValuePathLocator = RegisterContainerLocator<string>("SelectedValuePath", model => model.Initialize("SelectedValuePath", ref model._SelectedValuePath, ref _SelectedValuePathLocator, _SelectedValuePathDefaultValueFactory));
  294. static Func<string> _SelectedValuePathDefaultValueFactory = null;
  295. #endregion
  296. public object SelectedValue
  297. {
  298. get { return _SelectedValueLocator(this).Value; }
  299. set { _SelectedValueLocator(this).SetValueAndTryNotify(value); }
  300. }
  301. #region Property object SelectedValue Setup
  302. protected Property<object> _SelectedValue = new Property<object> { LocatorFunc = _SelectedValueLocator };
  303. static Func<BindableBase, ValueContainer<object>> _SelectedValueLocator = RegisterContainerLocator<object>("SelectedValue", model => model.Initialize("SelectedValue", ref model._SelectedValue, ref _SelectedValueLocator, _SelectedValueDefaultValueFactory));
  304. static Func<object> _SelectedValueDefaultValueFactory = null;
  305. #endregion
  306. public TCollection Items
  307. {
  308. get { return _ItemsLocator(this).Value; }
  309. set { _ItemsLocator(this).SetValueAndTryNotify(value); }
  310. }
  311. #region Property TCollection Items Setup
  312. protected Property<TCollection> _Items = new Property<TCollection> { LocatorFunc = _ItemsLocator };
  313. protected static Func<BindableBase, ValueContainer<TCollection>> _ItemsLocator = RegisterContainerLocator<TCollection>("Items", model => model.Initialize("Items", ref model._Items, ref _ItemsLocator, _ItemsDefaultValueFactory));
  314. protected static Func<TCollection> _ItemsDefaultValueFactory = null;
  315. #endregion
  316. public int SelectedIndex
  317. {
  318. get { return _SelectedIndexLocator(this).Value; }
  319. set { _SelectedIndexLocator(this).SetValueAndTryNotify(value); }
  320. }
  321. #region Property int SelectedIndex Setup
  322. protected Property<int> _SelectedIndex = new Property<int> { LocatorFunc = _SelectedIndexLocator };
  323. static Func<BindableBase, ValueContainer<int>> _SelectedIndexLocator = RegisterContainerLocator<int>("SelectedIndex", model => model.Initialize("SelectedIndex", ref model._SelectedIndex, ref _SelectedIndexLocator, _SelectedIndexDefaultValueFactory));
  324. static Func<int> _SelectedIndexDefaultValueFactory = () => -1;
  325. #endregion
  326. public T SelectedItem
  327. {
  328. get { return _SelectedItemLocator(this).Value; }
  329. set
  330. {
  331. _SelectedItemLocator(this).SetValueAndTryNotify(value);
  332. base.RaisePropertyChanged(() => new PropertyChangedEventArgs("SelectedItems"));
  333. }
  334. }
  335. #region Property T SelectedItem Setup
  336. protected Property<T> _SelectedItem = new Property<T> { LocatorFunc = _SelectedItemLocator };
  337. static Func<BindableBase, ValueContainer<T>> _SelectedItemLocator = RegisterContainerLocator<T>("SelectedItem", model => model.Initialize("SelectedItem", ref model._SelectedItem, ref _SelectedItemLocator, _SelectedItemDefaultValueFactory));
  338. static Func<T> _SelectedItemDefaultValueFactory = null;
  339. #endregion
  340. public IEnumerable SelectedItems
  341. {
  342. get
  343. {
  344. if (BindedTo != null)
  345. {
  346. try
  347. {
  348. #if WINDOWS_PHONE_7
  349. var m = BindedTo.GetType().GetProperty("SelectedItems");
  350. if (m!=null)
  351. {
  352. return m.GetValue(BindedTo,new object [0]) as IEnumerable;
  353. }
  354. #else
  355. dynamic x = BindedTo;
  356. return x.SelectedItems;
  357. #endif
  358. }
  359. catch (Exception)
  360. {
  361. }
  362. }
  363. return null;
  364. }
  365. }
  366. }
  367. }
  368. namespace Tree
  369. {
  370. public interface ITreeItem<out TNodeValue, TState>
  371. {
  372. TNodeValue Value { get; }
  373. TState State { get; set; }
  374. ITreeItem<Object, TState> Parent { get; }
  375. ICollection<ITreeItem<object, TState>> Children { get; }
  376. Type NodeValueType { get; }
  377. }
  378. //[DataContract(IsReference=true) ] //if you want
  379. public abstract class TreeItemModelBase<TNodeValue, TState, TSubType> :
  380. BindableBase<TSubType>,
  381. ITreeItem<TNodeValue, TState>
  382. where TSubType : TreeItemModelBase<TNodeValue, TState, TSubType>
  383. {
  384. public TreeItemModelBase()
  385. {
  386. }
  387. public Type NodeValueType
  388. {
  389. get
  390. {
  391. return typeof(TNodeValue);
  392. }
  393. }
  394. public TNodeValue Value
  395. {
  396. get { return _ValueLocator(this).Value; }
  397. set { _ValueLocator(this).SetValueAndTryNotify(value); }
  398. }
  399. #region Property TNodeValue Value Setup
  400. protected Property<TNodeValue> _Value = new Property<TNodeValue> { LocatorFunc = _ValueLocator };
  401. static Func<BindableBase, ValueContainer<TNodeValue>> _ValueLocator = RegisterContainerLocator<TNodeValue>("Value", model => model.Initialize("Value", ref model._Value, ref _ValueLocator, _ValueDefaultValueFactory));
  402. static Func<TNodeValue> _ValueDefaultValueFactory = null;
  403. #endregion
  404. public TState State
  405. {
  406. get { return _StateLocator(this).Value; }
  407. set { _StateLocator(this).SetValueAndTryNotify(value); }
  408. }
  409. #region Property TState State Setup
  410. protected Property<TState> _State = new Property<TState> { LocatorFunc = _StateLocator };
  411. static Func<BindableBase, ValueContainer<TState>> _StateLocator = RegisterContainerLocator<TState>("State", model => model.Initialize("State", ref model._State, ref _StateLocator, _StateDefaultValueFactory));
  412. static Func<TState> _StateDefaultValueFactory = null;
  413. #endregion
  414. public ITreeItem<object, TState> Parent
  415. {
  416. get { return _ParentLocator(this).Value; }
  417. set { _ParentLocator(this).SetValueAndTryNotify(value); }
  418. }
  419. #region Property INode<object, TState> Parent Setup
  420. protected Property<ITreeItem<object, TState>> _Parent = new Property<ITreeItem<object, TState>> { LocatorFunc = _ParentLocator };
  421. static Func<BindableBase, ValueContainer<ITreeItem<object, TState>>> _ParentLocator = RegisterContainerLocator<ITreeItem<object, TState>>("Parent", model => model.Initialize("Parent", ref model._Parent, ref _ParentLocator, _ParentDefaultValueFactory));
  422. static Func<ITreeItem<object, TState>> _ParentDefaultValueFactory = null;
  423. #endregion
  424. //public ObservableCollection<ITreeItem<object, TState>> Children
  425. //{
  426. // get { return _ChildrenLocator(this).Value; }
  427. // set { _ChildrenLocator(this).SetValueAndTryNotify(value); }
  428. //}
  429. //#region Property ObservableCollection<ITreeItem<object,TState >> Children Setup
  430. //protected Property<ObservableCollection<ITreeItem<object, TState>>> _Children = new Property<ObservableCollection<ITreeItem<object, TState>>> { LocatorFunc = _ChildrenLocator };
  431. //static Func<BindableBase, ValueContainer<ObservableCollection<ITreeItem<object, TState>>>> _ChildrenLocator = RegisterContainerLocator<ObservableCollection<ITreeItem<object, TState>>>("Children", model => model.Initialize("Children", ref model._Children, ref _ChildrenLocator, _ChildrenDefaultValueFactory));
  432. //static Func<ObservableCollection<ITreeItem<object, TState>>> _ChildrenDefaultValueFactory = () => new ObservableCollection<ITreeItem<object, TState>>();
  433. //#endregion
  434. public Collection<ITreeItem<object, TState>> Children
  435. {
  436. get { return _ChildrenLocator(this).Value; }
  437. set { _ChildrenLocator(this).SetValueAndTryNotify(value); }
  438. }
  439. #region Property Collection <ITreeItem<object, TState>> Children Setup
  440. protected Property<Collection<ITreeItem<object, TState>>> _Children = new Property<Collection<ITreeItem<object, TState>>> { LocatorFunc = _ChildrenLocator };
  441. static Func<BindableBase, ValueContainer<Collection<ITreeItem<object, TState>>>> _ChildrenLocator = RegisterContainerLocator<Collection<ITreeItem<object, TState>>>("Children", model => model.Initialize("Children", ref model._Children, ref _ChildrenLocator, _ChildrenDefaultValueFactory));
  442. static Func<Collection<ITreeItem<object, TState>>> _ChildrenDefaultValueFactory = () => new ObservableCollection<ITreeItem<object, TState>>();
  443. #endregion
  444. ICollection<ITreeItem<object, TState>> ITreeItem<TNodeValue, TState>.Children
  445. {
  446. get { return Children; }
  447. }
  448. }
  449. public class TreeViewItemModel<TValue> : TreeItemModelBase<TValue, TreeViewItemState, TreeViewItemModel<TValue>>
  450. {
  451. }
  452. public class TreeItemModel<TValue, TState> : TreeItemModelBase<TValue, TState, TreeItemModel<TValue, TState>>
  453. {
  454. }
  455. //[DataContract(IsReference=true) ] //if you want
  456. public class TreeViewItemState : BindableBase<TreeViewItemState>
  457. {
  458. public TreeViewItemState()
  459. {
  460. }
  461. public bool IsSelected
  462. {
  463. get { return _IsSelectedLocator(this).Value; }
  464. set { _IsSelectedLocator(this).SetValueAndTryNotify(value); }
  465. }
  466. #region Property bool IsSelected Setup
  467. protected Property<bool> _IsSelected = new Property<bool> { LocatorFunc = _IsSelectedLocator };
  468. static Func<BindableBase, ValueContainer<bool>> _IsSelectedLocator = RegisterContainerLocator<bool>("IsSelected", model => model.Initialize("IsSelected", ref model._IsSelected, ref _IsSelectedLocator, _IsSelectedDefaultValueFactory));
  469. static Func<bool> _IsSelectedDefaultValueFactory = null;
  470. #endregion
  471. public bool IsChecked
  472. {
  473. get { return _IsCheckedLocator(this).Value; }
  474. set { _IsCheckedLocator(this).SetValueAndTryNotify(value); }
  475. }
  476. #region Property bool IsChecked Setup
  477. protected Property<bool> _IsChecked = new Property<bool> { LocatorFunc = _IsCheckedLocator };
  478. static Func<BindableBase, ValueContainer<bool>> _IsCheckedLocator = RegisterContainerLocator<bool>("IsChecked", model => model.Initialize("IsChecked", ref model._IsChecked, ref _IsCheckedLocator, _IsCheckedDefaultValueFactory));
  479. static Func<bool> _IsCheckedDefaultValueFactory = null;
  480. #endregion
  481. public bool CanBeSelected
  482. {
  483. get { return _CanBeSelectedLocator(this).Value; }
  484. set { _CanBeSelectedLocator(this).SetValueAndTryNotify(value); }
  485. }
  486. #region Property bool CanBeSelected Setup
  487. protected Property<bool> _CanBeSelected = new Property<bool> { LocatorFunc = _CanBeSelectedLocator };
  488. static Func<BindableBase, ValueContainer<bool>> _CanBeSelectedLocator = RegisterContainerLocator<bool>("CanBeSelected", model => model.Initialize("CanBeSelected", ref model._CanBeSelected, ref _CanBeSelectedLocator, _CanBeSelectedDefaultValueFactory));
  489. static Func<bool> _CanBeSelectedDefaultValueFactory = null;
  490. #endregion
  491. }
  492. }
  493. }
  494. }