PageRenderTime 36ms CodeModel.GetById 2ms app.highlight 28ms RepoModel.GetById 1ms 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
  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.ViewModels;
 13using MVVMSidekick.Commands;
 14using System.Runtime.CompilerServices;
 15using MVVMSidekick.Reactive;
 16using System.Reactive.Linq;
 17using System.Reactive.Subjects;
 18using System.Reactive;
 19using MVVMSidekick.EventRouting;
 20using System.Collections.ObjectModel;
 21using System.Collections.Specialized;
 22using System.IO;
 23using System.Collections;
 24using System.Diagnostics;
 25using MVVMSidekick.Utilities;
 26using System.Windows;
 27
 28#if NETFX_CORE
 29using Windows.UI.Xaml;
 30using Windows.UI.Xaml.Data;
 31using Windows.UI.Xaml.Controls;
 32using System.Collections.Concurrent;
 33using Windows.UI.Xaml.Navigation;
 34using Windows.UI.Xaml.Controls.Primitives;
 35
 36
 37
 38#elif WPF
 39
 40using System.Windows.Controls;
 41using System.Windows.Data;
 42using System.Collections.Concurrent;
 43using System.Windows.Navigation;
 44
 45using MVVMSidekick.Views;
 46using System.Windows.Controls.Primitives;
 47
 48
 49
 50#elif SILVERLIGHT_5||SILVERLIGHT_4
 51using System.Windows;
 52using System.Windows.Controls;
 53using System.Windows.Data;
 54using System.Windows.Navigation;
 55using System.Windows.Controls.Primitives;
 56#elif WINDOWS_PHONE_8||WINDOWS_PHONE_7
 57using System.Windows;
 58using System.Windows.Controls;
 59using Microsoft.Phone.Controls;
 60using System.Windows.Data;
 61using System.Windows.Navigation;
 62using System.Windows.Controls;
 63using System.Windows.Data;
 64using System.Windows.Controls.Primitives;
 65#endif
 66
 67namespace MVVMSidekick
 68{
 69
 70	namespace Patterns
 71	{
 72
 73		public class ElementBinderBase<TSubType> : DependencyObject, IDisposable where
 74			TSubType : ElementBinderBase<TSubType>
 75		{
 76			public ElementBinderBase() { }
 77			public ElementBinderBase(Action<TSubType> bindingAction, Action<TSubType> disposeAction)
 78			{
 79				_bindingAction = bindingAction;
 80				_disposeAction = ts =>
 81				{
 82					disposeAction(ts);
 83
 84				};
 85			}
 86			protected Action<TSubType> _bindingAction;
 87			protected Action<TSubType> _disposeAction;
 88
 89
 90
 91
 92			protected static PropertyChangedCallback BinderPropertyChangedCallback = (o, e) =>
 93					{
 94						if (e.NewValue is TSubType)
 95						{
 96							var eb = e.NewValue as TSubType;
 97							eb.Element = o as FrameworkElement;
 98
 99							if (eb._bindingAction != null)
100							{
101								try
102								{
103									eb._bindingAction(eb);
104								}
105								catch (Exception ex)
106								{
107
108									Debug.WriteLine(ex);
109								}
110								finally
111								{
112									eb._bindingAction = null;
113								}
114
115
116							}
117						}
118
119					};
120
121
122
123
124
125
126
127			public FrameworkElement Element
128			{
129				get { return (FrameworkElement)GetValue(ElementProperty); }
130				set { SetValue(ElementProperty, value); }
131			}
132
133			// Using a DependencyProperty as the backing store for Element.  This enables animation, styling, binding, etc...
134			public static readonly DependencyProperty ElementProperty =
135				DependencyProperty.Register("Element", typeof(FrameworkElement), typeof(TSubType), new PropertyMetadata(null));
136
137
138
139
140
141
142
143
144			#region IDisposable Members
145
146			int _Disposed = 0;
147			~ElementBinderBase()
148			{
149				Dispose(false);
150			}
151			public void Dispose()
152			{
153				Dispose(true);
154				GC.SuppressFinalize(this);
155			}
156
157			virtual protected  void Dispose(bool disposing)
158			{
159				var v = Interlocked.Exchange(ref _Disposed, 1);
160				if (v == 0)
161				{
162					try
163					{
164						if (_disposeAction != null)
165						{
166							_disposeAction(this as TSubType);
167
168						}
169					}
170					catch (Exception ex)
171					{
172						Debug.WriteLine(ex);
173					}
174					finally
175					{
176						_disposeAction = null;
177
178					}
179					_disposeAction = null;
180					_bindingAction = null;
181				}
182
183			}
184
185
186
187			#endregion
188		}
189
190		namespace ItemsAndSelection
191		{
192
193
194			public class ItemsAndSelectionGroup<T> : ItemsAndSelectionGroup<T, ObservableCollection<T>, SelectionMode>
195			{
196				static ItemsAndSelectionGroup()
197				{
198					_ItemsDefaultValueFactory = () => new ObservableCollection<T>();
199
200				}
201			}
202
203
204			public class ItemsAndSelectionGroupBinder : ElementBinderBase<ItemsAndSelectionGroupBinder>
205			{
206				public ItemsAndSelectionGroupBinder(Action<ItemsAndSelectionGroupBinder> bindingAction, Action<ItemsAndSelectionGroupBinder> disposeAction)
207					: base(bindingAction, disposeAction)
208				{ }
209
210
211				public static ItemsAndSelectionGroupBinder GetBinder(DependencyObject obj)
212				{
213					return (ItemsAndSelectionGroupBinder)obj.GetValue(BinderProperty);
214				}
215
216				public static void SetBinder(DependencyObject obj, ItemsAndSelectionGroupBinder value)
217				{
218					obj.SetValue(BinderProperty, value);
219				}
220
221				// Using a DependencyProperty as the backing store for ElementBinder.  This enables animation, styling, binding, etc...
222				public static readonly DependencyProperty BinderProperty =
223					DependencyProperty.RegisterAttached("Binder", typeof(ItemsAndSelectionGroupBinder), typeof(ItemsAndSelectionGroupBinder), new PropertyMetadata(
224						null,
225						BinderPropertyChangedCallback));
226
227
228			}
229
230			public interface IItemsAndSelectionGroupBinding
231			{
232				MVVMSidekick.Patterns.ItemsAndSelection.ItemsAndSelectionGroupBinder Binder { get; set; }
233			}
234
235			public class ItemsAndSelectionGroup<T, TCollection, TSelectionMode> : BindableBase<ItemsAndSelectionGroup<T, TCollection, TSelectionMode>>, IItemsAndSelectionGroupBinding
236				where TCollection : ICollection<T>, INotifyCollectionChanged
237			{
238
239				public ItemsAndSelectionGroup()
240				{
241
242					base.AddDisposeAction(() => Binder = null);
243					this.GetValueContainer(x => x.Items).GetNullObservable()
244						.Subscribe(_ => ResetSelection())
245						.DisposeWith(this);
246
247				}
248
249
250				private void ResetSelection()
251				{
252					ResetPropertyValue(_SelectedValue);
253					ResetPropertyValue(_SelectedIndex);
254					ResetPropertyValue(_SelectedItem);
255
256				}
257
258
259				public ItemsAndSelectionGroupBinder Binder
260				{
261					get { return _BinderLocator(this).Value; }
262					set { _BinderLocator(this).SetValueAndTryNotify(value); }
263				}
264				#region Property ElementBinder Binder Setup
265				protected Property<ItemsAndSelectionGroupBinder> _Binder = new Property<ItemsAndSelectionGroupBinder> { LocatorFunc = _BinderLocator };
266				static Func<BindableBase, ValueContainer<ItemsAndSelectionGroupBinder>> _BinderLocator = RegisterContainerLocator<ItemsAndSelectionGroupBinder>("Binder", model => model.Initialize("Binder", ref model._Binder, ref _BinderLocator, _BinderDefaultValueFactory));
267				static Func<BindableBase, ItemsAndSelectionGroupBinder> _BinderDefaultValueFactory = model =>
268					{
269						var vm = CastToCurrentType(model);
270
271						Action<ItemsAndSelectionGroupBinder> bindingAc =
272							 eb =>
273							 {
274
275
276								 var ls = eb.Element as ItemsControl;
277								 if (ls == null)
278								 {
279									 return;
280								 }
281
282
283								 if (vm == null)
284								 {
285									 return;
286								 }
287
288
289								 var itemsBinding = new Binding()
290								 {
291									 Source = vm,
292									 Mode = BindingMode.OneWay,
293									 Path = new PropertyPath("Items")
294								 };
295
296								 BindingOperations.SetBinding(ls, ItemsControl.ItemsSourceProperty, itemsBinding);
297
298
299
300								 if (!(ls is Selector))
301								 {
302									 return;
303								 }
304
305
306
307								 var selectedBinding = new Binding()
308								 {
309									 Source = vm,
310									 Mode = BindingMode.TwoWay,
311									 Path = new PropertyPath("SelectedItem")
312								 };
313
314								 BindingOperations.SetBinding(ls, Selector.SelectedItemProperty, selectedBinding);
315
316
317								 var selectedindexBinding = new Binding()
318								 {
319									 Source = vm,
320									 Mode = BindingMode.TwoWay,
321									 Path = new PropertyPath("SelectedIndex")
322								 };
323
324								 BindingOperations.SetBinding(ls, Selector.SelectedIndexProperty, selectedindexBinding);
325
326
327
328								 var selectedValuePathBinding = new Binding()
329								 {
330									 Source = vm,
331									 Mode = BindingMode.TwoWay,
332									 Path = new PropertyPath("SelectedValuePath")
333								 };
334
335								 BindingOperations.SetBinding(ls, Selector.SelectedValuePathProperty, selectedValuePathBinding);
336
337								 var selectedValueBinding = new Binding()
338								 {
339									 Source = vm,
340									 Mode = BindingMode.TwoWay,
341									 Path = new PropertyPath("SelectedValue")
342								 };
343
344								 BindingOperations.SetBinding(ls, Selector.SelectedValueProperty, selectedValueBinding);
345#if SILVERLIGHT_5 || WINDOWS_PHONE_8||WINDOWS_PHONE_7
346                                 if (!(ls is ListBox))
347#else
348								 if (!(ls is ListBox) && (!(ls is ListView)))
349#endif
350
351								 {
352									 return;
353								 }
354
355								 var selectionModeBinding = new Binding()
356								 {
357									 Source = vm,
358									 Mode = BindingMode.TwoWay,
359									 Path = new PropertyPath("SelectionMode")
360								 };
361
362								 BindingOperations.SetBinding(ls, ListBox.SelectionModeProperty, selectionModeBinding);
363
364							 };
365
366
367						return new ItemsAndSelectionGroupBinder(bindingAc, (e) => e.Element = null).DisposeWith(vm);
368
369					};
370
371				#endregion
372
373
374
375				public FrameworkElement BindedTo
376				{
377					get { return Binder.Element; }
378
379				}
380
381
382
383				public TSelectionMode SelectionMode
384				{
385					get { return _SelectionModeLocator(this).Value; }
386					set { _SelectionModeLocator(this).SetValueAndTryNotify(value); }
387				}
388				#region Property TSelectionMode SelectionMode Setup
389				protected Property<TSelectionMode> _SelectionMode = new Property<TSelectionMode> { LocatorFunc = _SelectionModeLocator };
390				static Func<BindableBase, ValueContainer<TSelectionMode>> _SelectionModeLocator = RegisterContainerLocator<TSelectionMode>("SelectionMode", model => model.Initialize("SelectionMode", ref model._SelectionMode, ref _SelectionModeLocator, _SelectionModeDefaultValueFactory));
391				static Func<TSelectionMode> _SelectionModeDefaultValueFactory = null;
392				#endregion
393
394
395
396
397				public string SelectedValuePath
398				{
399					get { return _SelectedValuePathLocator(this).Value; }
400					set { _SelectedValuePathLocator(this).SetValueAndTryNotify(value); }
401				}
402				#region Property string SelectedValuePath Setup
403				protected Property<string> _SelectedValuePath = new Property<string> { LocatorFunc = _SelectedValuePathLocator };
404				static Func<BindableBase, ValueContainer<string>> _SelectedValuePathLocator = RegisterContainerLocator<string>("SelectedValuePath", model => model.Initialize("SelectedValuePath", ref model._SelectedValuePath, ref _SelectedValuePathLocator, _SelectedValuePathDefaultValueFactory));
405				static Func<string> _SelectedValuePathDefaultValueFactory = null;
406				#endregion
407
408
409				public object SelectedValue
410				{
411					get { return _SelectedValueLocator(this).Value; }
412					set { _SelectedValueLocator(this).SetValueAndTryNotify(value); }
413				}
414				#region Property object SelectedValue Setup
415				protected Property<object> _SelectedValue = new Property<object> { LocatorFunc = _SelectedValueLocator };
416				static Func<BindableBase, ValueContainer<object>> _SelectedValueLocator = RegisterContainerLocator<object>("SelectedValue", model => model.Initialize("SelectedValue", ref model._SelectedValue, ref _SelectedValueLocator, _SelectedValueDefaultValueFactory));
417				static Func<object> _SelectedValueDefaultValueFactory = null;
418				#endregion
419
420
421
422
423				public TCollection Items
424				{
425					get { return _ItemsLocator(this).Value; }
426					set { _ItemsLocator(this).SetValueAndTryNotify(value); }
427				}
428				#region Property TCollection Items Setup
429				protected Property<TCollection> _Items = new Property<TCollection> { LocatorFunc = _ItemsLocator };
430				protected static Func<BindableBase, ValueContainer<TCollection>> _ItemsLocator = RegisterContainerLocator<TCollection>("Items", model => model.Initialize("Items", ref model._Items, ref _ItemsLocator, _ItemsDefaultValueFactory));
431				protected static Func<TCollection> _ItemsDefaultValueFactory = null;
432				#endregion
433
434
435
436
437				public int SelectedIndex
438				{
439					get { return _SelectedIndexLocator(this).Value; }
440					set { _SelectedIndexLocator(this).SetValueAndTryNotify(value); }
441				}
442				#region Property int SelectedIndex Setup
443				protected Property<int> _SelectedIndex = new Property<int> { LocatorFunc = _SelectedIndexLocator };
444				static Func<BindableBase, ValueContainer<int>> _SelectedIndexLocator = RegisterContainerLocator<int>("SelectedIndex", model => model.Initialize("SelectedIndex", ref model._SelectedIndex, ref _SelectedIndexLocator, _SelectedIndexDefaultValueFactory));
445				static Func<int> _SelectedIndexDefaultValueFactory = () => -1;
446				#endregion
447
448
449
450				public T SelectedItem
451				{
452					get { return _SelectedItemLocator(this).Value; }
453					set
454					{
455						_SelectedItemLocator(this).SetValueAndTryNotify(value);
456						base.RaisePropertyChanged(() => new PropertyChangedEventArgs("SelectedItems"));
457					}
458				}
459				#region Property T SelectedItem Setup
460				protected Property<T> _SelectedItem = new Property<T> { LocatorFunc = _SelectedItemLocator };
461				static Func<BindableBase, ValueContainer<T>> _SelectedItemLocator = RegisterContainerLocator<T>("SelectedItem", model => model.Initialize("SelectedItem", ref model._SelectedItem, ref _SelectedItemLocator, _SelectedItemDefaultValueFactory));
462				static Func<T> _SelectedItemDefaultValueFactory = null;
463				#endregion
464
465
466				public IEnumerable SelectedItems
467				{
468					get
469					{
470						if (BindedTo != null)
471						{
472
473							try
474							{
475#if WINDOWS_PHONE_7
476                                var m = BindedTo.GetType().GetProperty("SelectedItems");
477                                if (m!=null)
478                                {
479                                    return m.GetValue(BindedTo,new object [0]) as IEnumerable;
480                                }
481                               
482#else
483								dynamic x = BindedTo;
484								return x.SelectedItems;
485#endif
486
487							}
488							catch (Exception)
489							{
490
491
492							}
493
494						}
495						return null;
496					}
497				}
498
499
500
501
502
503
504
505
506
507
508			}
509		}
510
511
512		namespace Tree
513		{
514			public interface ITreeItem<out TNodeValue, TState>
515			{
516				TNodeValue Value { get; }
517				TState State { get; set; }
518				ITreeItem<Object, TState> Parent { get; }
519				ICollection<ITreeItem<object, TState>> Children { get; }
520				Type NodeValueType { get; }
521			}
522
523
524
525			//[DataContract(IsReference=true) ] //if you want
526			public abstract class TreeItemModelBase<TNodeValue, TState, TSubType> :
527				BindableBase<TSubType>,
528				ITreeItem<TNodeValue, TState>
529				where TSubType : TreeItemModelBase<TNodeValue, TState, TSubType>
530			{
531				public TreeItemModelBase()
532				{
533
534				}
535
536
537
538
539
540
541				public Type NodeValueType
542				{
543					get
544					{
545						return typeof(TNodeValue);
546					}
547				}
548
549				public TNodeValue Value
550				{
551					get { return _ValueLocator(this).Value; }
552					set { _ValueLocator(this).SetValueAndTryNotify(value); }
553				}
554				#region Property TNodeValue Value Setup
555				protected Property<TNodeValue> _Value = new Property<TNodeValue> { LocatorFunc = _ValueLocator };
556				static Func<BindableBase, ValueContainer<TNodeValue>> _ValueLocator = RegisterContainerLocator<TNodeValue>("Value", model => model.Initialize("Value", ref model._Value, ref _ValueLocator, _ValueDefaultValueFactory));
557				static Func<TNodeValue> _ValueDefaultValueFactory = null;
558				#endregion
559
560
561
562				public TState State
563				{
564					get { return _StateLocator(this).Value; }
565					set { _StateLocator(this).SetValueAndTryNotify(value); }
566				}
567				#region Property TState State Setup
568				protected Property<TState> _State = new Property<TState> { LocatorFunc = _StateLocator };
569				static Func<BindableBase, ValueContainer<TState>> _StateLocator = RegisterContainerLocator<TState>("State", model => model.Initialize("State", ref model._State, ref _StateLocator, _StateDefaultValueFactory));
570				static Func<TState> _StateDefaultValueFactory = null;
571				#endregion
572
573
574
575				public ITreeItem<object, TState> Parent
576				{
577					get { return _ParentLocator(this).Value; }
578					set { _ParentLocator(this).SetValueAndTryNotify(value); }
579				}
580				#region Property INode<object, TState> Parent Setup
581				protected Property<ITreeItem<object, TState>> _Parent = new Property<ITreeItem<object, TState>> { LocatorFunc = _ParentLocator };
582				static Func<BindableBase, ValueContainer<ITreeItem<object, TState>>> _ParentLocator = RegisterContainerLocator<ITreeItem<object, TState>>("Parent", model => model.Initialize("Parent", ref model._Parent, ref _ParentLocator, _ParentDefaultValueFactory));
583				static Func<ITreeItem<object, TState>> _ParentDefaultValueFactory = null;
584				#endregion
585
586
587
588
589				//public ObservableCollection<ITreeItem<object, TState>> Children
590				//{
591				//    get { return _ChildrenLocator(this).Value; }
592				//    set { _ChildrenLocator(this).SetValueAndTryNotify(value); }
593				//}
594				//#region Property ObservableCollection<ITreeItem<object,TState >> Children Setup
595				//protected Property<ObservableCollection<ITreeItem<object, TState>>> _Children = new Property<ObservableCollection<ITreeItem<object, TState>>> { LocatorFunc = _ChildrenLocator };
596				//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));
597				//static Func<ObservableCollection<ITreeItem<object, TState>>> _ChildrenDefaultValueFactory = () => new ObservableCollection<ITreeItem<object, TState>>();
598				//#endregion
599
600
601
602				public Collection<ITreeItem<object, TState>> Children
603				{
604					get { return _ChildrenLocator(this).Value; }
605					set { _ChildrenLocator(this).SetValueAndTryNotify(value); }
606				}
607				#region Property Collection <ITreeItem<object, TState>> Children Setup
608				protected Property<Collection<ITreeItem<object, TState>>> _Children = new Property<Collection<ITreeItem<object, TState>>> { LocatorFunc = _ChildrenLocator };
609				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));
610				static Func<Collection<ITreeItem<object, TState>>> _ChildrenDefaultValueFactory = () => new ObservableCollection<ITreeItem<object, TState>>();
611				#endregion
612
613
614				ICollection<ITreeItem<object, TState>> ITreeItem<TNodeValue, TState>.Children
615				{
616					get { return Children; }
617				}
618			}
619
620
621
622
623			public class TreeViewItemModel<TValue> : TreeItemModelBase<TValue, TreeViewItemState, TreeViewItemModel<TValue>>
624			{
625
626			}
627
628
629			public class TreeItemModel<TValue, TState> : TreeItemModelBase<TValue, TState, TreeItemModel<TValue, TState>>
630			{
631
632			}
633
634
635
636
637
638
639
640			//[DataContract(IsReference=true) ] //if you want
641			public class TreeViewItemState : BindableBase<TreeViewItemState>
642			{
643				public TreeViewItemState()
644				{
645
646
647				}
648
649				public bool IsSelected
650				{
651					get { return _IsSelectedLocator(this).Value; }
652					set { _IsSelectedLocator(this).SetValueAndTryNotify(value); }
653				}
654				#region Property bool IsSelected Setup
655				protected Property<bool> _IsSelected = new Property<bool> { LocatorFunc = _IsSelectedLocator };
656				static Func<BindableBase, ValueContainer<bool>> _IsSelectedLocator = RegisterContainerLocator<bool>("IsSelected", model => model.Initialize("IsSelected", ref model._IsSelected, ref _IsSelectedLocator, _IsSelectedDefaultValueFactory));
657				static Func<bool> _IsSelectedDefaultValueFactory = null;
658				#endregion
659
660
661				public bool IsChecked
662				{
663					get { return _IsCheckedLocator(this).Value; }
664					set { _IsCheckedLocator(this).SetValueAndTryNotify(value); }
665				}
666				#region Property bool IsChecked Setup
667				protected Property<bool> _IsChecked = new Property<bool> { LocatorFunc = _IsCheckedLocator };
668				static Func<BindableBase, ValueContainer<bool>> _IsCheckedLocator = RegisterContainerLocator<bool>("IsChecked", model => model.Initialize("IsChecked", ref model._IsChecked, ref _IsCheckedLocator, _IsCheckedDefaultValueFactory));
669				static Func<bool> _IsCheckedDefaultValueFactory = null;
670				#endregion
671
672
673				public bool CanBeSelected
674				{
675					get { return _CanBeSelectedLocator(this).Value; }
676					set { _CanBeSelectedLocator(this).SetValueAndTryNotify(value); }
677				}
678				#region Property bool CanBeSelected Setup
679				protected Property<bool> _CanBeSelected = new Property<bool> { LocatorFunc = _CanBeSelectedLocator };
680				static Func<BindableBase, ValueContainer<bool>> _CanBeSelectedLocator = RegisterContainerLocator<bool>("CanBeSelected", model => model.Initialize("CanBeSelected", ref model._CanBeSelected, ref _CanBeSelectedLocator, _CanBeSelectedDefaultValueFactory));
681				static Func<bool> _CanBeSelectedDefaultValueFactory = null;
682				#endregion
683
684
685
686
687			}
688
689		}
690
691
692
693
694
695
696
697	}
698
699
700}