PageRenderTime 60ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/MVVMSidekick/MVVMSidekick.Shared/Views.cs

https://github.com/zoujuny/MVVM-Sidekick
C# | 1899 lines | 1308 code | 460 blank | 131 comment | 139 complexity | ce3f16a370eb484ac5acbbe4718a83f2 MD5 | raw file

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.ComponentModel;
  6. using System.Linq.Expressions;
  7. using System.Runtime.Serialization;
  8. using System.Reflection;
  9. using System.Threading.Tasks;
  10. using System.Threading;
  11. using System.Windows.Input;
  12. using MVVMSidekick.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.Windows;
  25. #if NETFX_CORE
  26. using Windows.UI.Xaml;
  27. using Windows.UI.Xaml.Data;
  28. using Windows.UI.Xaml.Controls;
  29. using System.Collections.Concurrent;
  30. using Windows.UI.Xaml.Navigation;
  31. using Windows.UI.Xaml.Controls.Primitives;
  32. #elif WPF
  33. using System.Windows.Controls;
  34. using System.Collections.Concurrent;
  35. using System.Windows.Navigation;
  36. using MVVMSidekick.Views;
  37. using System.Windows.Controls.Primitives;
  38. using MVVMSidekick.Utilities;
  39. #elif SILVERLIGHT_5||SILVERLIGHT_4
  40. using System.Windows;
  41. using System.Windows.Controls;
  42. using System.Windows.Data;
  43. using System.Windows.Navigation;
  44. using System.Windows.Controls.Primitives;
  45. #elif WINDOWS_PHONE_8||WINDOWS_PHONE_7
  46. using System.Windows;
  47. using System.Windows.Controls;
  48. using Microsoft.Phone.Controls;
  49. using System.Windows.Data;
  50. using System.Windows.Navigation;
  51. using System.Windows.Controls.Primitives;
  52. #endif
  53. #if (! WPF) && (! NETFX_CORE)
  54. namespace System.Windows
  55. {
  56. }
  57. #endif
  58. namespace MVVMSidekick
  59. {
  60. namespace Views
  61. {
  62. public static class ViewHelper
  63. {
  64. public static readonly string DEFAULT_VM_NAME = "DesignVM";
  65. public static object GetDefaultDesigningViewModel(this IView view)
  66. {
  67. var f = view as FrameworkElement;
  68. object rval = null;
  69. #if NETFX_CORE
  70. if (!f.Resources.ContainsKey(DEFAULT_VM_NAME))
  71. #else
  72. if (!f.Resources.Contains(DEFAULT_VM_NAME))
  73. #endif
  74. {
  75. return null;
  76. }
  77. else
  78. {
  79. rval = f.Resources[DEFAULT_VM_NAME];
  80. }
  81. return rval;
  82. }
  83. internal static RoutedEventHandler ViewUnloadCallBack
  84. = async (o, e) =>
  85. {
  86. IView v = o as IView;
  87. if (v != null)
  88. {
  89. var m = v.ViewModel as IViewModelLifetime;
  90. if (m != null)
  91. {
  92. await m.OnBindedViewUnload(v);
  93. }
  94. }
  95. };
  96. internal static PropertyChangedCallback DesigningViewModelChangedCallBack
  97. = (o, e) =>
  98. {
  99. var oiview = o as IView;
  100. if (Utilities.Runtime.IsInDesignMode)
  101. {
  102. oiview.ViewModel = e.NewValue as IViewModel;
  103. }
  104. };
  105. internal static PropertyChangedCallback ViewModelChangedCallback
  106. = (o, e) =>
  107. {
  108. dynamic item = o;
  109. var oiview = o as IView;
  110. var fele = (oiview.ContentObject as FrameworkElement);
  111. if (fele==null)
  112. {
  113. return;
  114. }
  115. if (object.ReferenceEquals(fele.DataContext, e.NewValue))
  116. {
  117. return;
  118. }
  119. (oiview.ContentObject as FrameworkElement).DataContext = e.NewValue;
  120. var nv = e.NewValue as IViewModel;
  121. var ov = e.OldValue as IViewModel;
  122. if (ov != null)
  123. {
  124. ov.OnUnbindedFromView(oiview, nv);
  125. }
  126. if (nv != null)
  127. {
  128. nv.OnBindedToView(oiview, ov);
  129. }
  130. };
  131. internal static FrameworkElement GetContentAndCreateIfNull(this IView control)
  132. {
  133. var c = (control.ContentObject as FrameworkElement);
  134. if (c == null)
  135. {
  136. control.ContentObject = c = new Grid();
  137. }
  138. return c;
  139. }
  140. public static void SelfClose(this IView view)
  141. {
  142. view.ViewModel = null;
  143. if (view is UserControl || view is Page)
  144. {
  145. var viewElement = view as FrameworkElement;
  146. var parent = viewElement.Parent;
  147. if (parent is Panel)
  148. {
  149. (parent as Panel).Children.Remove(viewElement);
  150. }
  151. else if (parent is Frame)
  152. {
  153. var f = (parent as Frame);
  154. if (f.CanGoBack)
  155. {
  156. f.GoBack();
  157. }
  158. else
  159. {
  160. f.Content = null;
  161. }
  162. }
  163. else if (parent is ContentControl)
  164. {
  165. (parent as ContentControl).Content = null;
  166. }
  167. else if (parent is Page)
  168. {
  169. (parent as Page).Content = null;
  170. }
  171. else if (parent is UserControl)
  172. {
  173. (parent as UserControl).Content = null;
  174. }
  175. }
  176. #if WPF
  177. else if (view is Window)
  178. {
  179. (view as Window).Close();
  180. }
  181. #endif
  182. }
  183. }
  184. #if WPF
  185. public class MVVMWindow : Window, IView
  186. {
  187. public MVVMWindow()
  188. : this(null)
  189. {
  190. }
  191. public MVVMWindow(IViewModel viewModel)
  192. {
  193. Unloaded += ViewHelper.ViewUnloadCallBack;
  194. Loaded += async (_1, _2) =>
  195. {
  196. // if (viewModel != null)
  197. // {
  198. // // this.Resources[ViewHelper.DEFAULT_VM_NAME] = viewModel;
  199. // if (!object.ReferenceEquals(ViewModel, viewModel))
  200. // {
  201. // ViewModel = viewModel;
  202. // }
  203. // }
  204. // else
  205. // {
  206. // var solveV = this.GetDefaultViewModel();
  207. // if (solveV != null)
  208. // {
  209. // ViewModel = solveV;
  210. // }
  211. // }
  212. // ////ViewModel = ViewModel ?? new DefaultViewModel();
  213. await ViewModel.OnBindedViewLoad(this);
  214. };
  215. }
  216. public object ContentObject
  217. {
  218. get
  219. {
  220. return Content;
  221. }
  222. set
  223. {
  224. Content = value;
  225. }
  226. }
  227. //public IViewModel DesigningViewModel
  228. //{
  229. // get { return (IViewModel)GetValue(DesigningViewModelProperty); }
  230. // set { SetValue(DesigningViewModelProperty, value); }
  231. //}
  232. //// Using a DependencyProperty as the backing store for DesigningViewModel. This enables animation, styling, binding, etc...
  233. //public static readonly DependencyProperty DesigningViewModelProperty =
  234. // DependencyProperty.Register("DesigningViewModel", typeof(IViewModel), typeof(MVVMWindow), new PropertyMetadata(null, ViewHelper.DesigningViewModelChangedCallBack));
  235. public IViewModel ViewModel
  236. {
  237. get
  238. {
  239. var rval = GetValue(ViewModelProperty) as IViewModel;
  240. var c = this.GetContentAndCreateIfNull();
  241. if (rval == null)
  242. {
  243. rval = c.DataContext as IViewModel;
  244. SetValue(ViewModelProperty, rval);
  245. }
  246. else
  247. {
  248. if (!Object.ReferenceEquals(c.DataContext, rval))
  249. {
  250. c.DataContext = rval;
  251. }
  252. }
  253. return rval;
  254. }
  255. set
  256. {
  257. SetValue(ViewModelProperty, value);
  258. var c = this.GetContentAndCreateIfNull();
  259. if (!Object.ReferenceEquals(c.DataContext, value))
  260. {
  261. c.DataContext = value;
  262. }
  263. }
  264. }
  265. // Using a DependencyProperty as the backing store for ViewModel. This enables animation, styling, binding, etc...
  266. public static readonly DependencyProperty ViewModelProperty =
  267. DependencyProperty.Register("ViewModel", typeof(IViewModel), typeof(MVVMWindow), new PropertyMetadata(null, ViewHelper.ViewModelChangedCallback));
  268. public ViewType ViewType
  269. {
  270. get { return ViewType.Window; }
  271. }
  272. }
  273. #endif
  274. #if WINDOWS_PHONE_7||WINDOWS_PHONE_8
  275. public partial class MVVMPage : PhoneApplicationPage, IView
  276. #else
  277. public class MVVMPage : Page, IView
  278. #endif
  279. {
  280. public MVVMPage()
  281. : this(null)
  282. {
  283. }
  284. #if WPF
  285. public Frame Frame
  286. {
  287. get { return (Frame)GetValue(FrameProperty); }
  288. set { SetValue(FrameProperty, value); }
  289. }
  290. // Using a DependencyProperty as the backing store for Frame. This enables animation, styling, binding, etc...
  291. public static readonly DependencyProperty FrameProperty =
  292. DependencyProperty.Register("Frame", typeof(Frame), typeof(MVVMPage), new PropertyMetadata(null));
  293. DependencyObject IView.Parent
  294. {
  295. get
  296. {
  297. return Frame;
  298. }
  299. }
  300. #endif
  301. public MVVMPage(IViewModel viewModel)
  302. {
  303. ViewModel = viewModel;
  304. Unloaded += ViewHelper.ViewUnloadCallBack;
  305. #if WPF
  306. Loaded += async (o, e) =>
  307. {
  308. await ViewModel.OnBindedViewLoad(this);
  309. };
  310. #endif
  311. }
  312. #if ! WPF
  313. //WPF Pages' Content are objects but others are FE .
  314. public object ContentObject
  315. {
  316. get { return Content; }
  317. set { Content = value as FrameworkElement; }
  318. }
  319. bool IsLoaded = false;
  320. //WPF navigates page instances but other navgates with parameters
  321. protected override void OnNavigatedTo(NavigationEventArgs e)
  322. {
  323. base.OnNavigatedTo(e);
  324. RoutedEventHandler loadEvent = null;
  325. loadEvent = async (_1, _2) =>
  326. {
  327. EventRouting.EventRouter.Instance.RaiseEvent(this, e);
  328. if (ViewModel != null)
  329. {
  330. await ViewModel.OnBindedViewLoad(this);
  331. }
  332. IsLoaded = true;
  333. this.Loaded -= loadEvent;
  334. };
  335. this.Loaded += loadEvent;
  336. }
  337. protected override void OnNavigatedFrom(NavigationEventArgs e)
  338. {
  339. base.OnNavigatedFrom(e);
  340. #if SILVERLIGHT_5
  341. if (ViewModel.StageManager.DefaultStage.NavigateRequestContexts.ContainsKey(e.Uri.ToString()))
  342. #else
  343. if (e.NavigationMode == NavigationMode.Back)
  344. #endif
  345. {
  346. if (ViewModel != null)
  347. {
  348. ViewModel.Dispose();
  349. }
  350. }
  351. }
  352. #else
  353. public object ContentObject
  354. {
  355. get
  356. {
  357. return Content;
  358. }
  359. set
  360. {
  361. Content = value;
  362. }
  363. }
  364. #endif
  365. //public IViewModel DesigningViewModel
  366. //{
  367. // get { return (IViewModel)GetValue(DesigningViewModelProperty); }
  368. // set { SetValue(DesigningViewModelProperty, value); }
  369. //}
  370. //// Using a DependencyProperty as the backing store for DesigningViewModel. This enables animation, styling, binding, etc...
  371. //public static readonly DependencyProperty DesigningViewModelProperty =
  372. // DependencyProperty.Register("DesigningViewModel", typeof(IViewModel), typeof(MVVMPage), new PropertyMetadata(null, ViewHelper.DesigningViewModelChangedCallBack));
  373. public IViewModel ViewModel
  374. {
  375. get
  376. {
  377. var rval = GetValue(ViewModelProperty) as IViewModel;
  378. var c = this.GetContentAndCreateIfNull();
  379. if (rval == null)
  380. {
  381. rval = c.DataContext as IViewModel;
  382. SetValue(ViewModelProperty, rval);
  383. }
  384. else
  385. {
  386. if (!Object.ReferenceEquals(c.DataContext, rval))
  387. {
  388. c.DataContext = rval;
  389. }
  390. }
  391. return rval;
  392. }
  393. set
  394. {
  395. SetValue(ViewModelProperty, value);
  396. var c = this.GetContentAndCreateIfNull();
  397. if (!Object.ReferenceEquals(c.DataContext, value))
  398. {
  399. c.DataContext = value;
  400. }
  401. }
  402. }
  403. // Using a DependencyProperty as the backing store for ViewModel. This enables animation, styling, binding, etc...
  404. public static readonly DependencyProperty ViewModelProperty =
  405. DependencyProperty.Register("ViewModel", typeof(IViewModel), typeof(MVVMPage), new PropertyMetadata(null,
  406. (o, e) =>
  407. {
  408. var p = o as MVVMPage;
  409. #if !WPF
  410. if (p.IsLoaded)
  411. {
  412. ViewHelper.ViewModelChangedCallback(o, e);
  413. }
  414. #else
  415. ViewHelper.ViewModelChangedCallback(o, e);
  416. #endif
  417. }
  418. ));
  419. #if NETFX_CORE
  420. /// <summary>
  421. /// Populates the page with content passed during navigation. Any saved state is also
  422. /// provided when recreating a page from a prior session.
  423. /// </summary>
  424. /// <param name="navigationParameter">The parameter value passed to
  425. /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
  426. /// </param>
  427. /// <param name="pageState">A dictionary of state preserved by this page during an earlier
  428. /// session. This will be null the first time a page is visited.</param>
  429. protected virtual void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
  430. {
  431. if (ViewModel != null)
  432. {
  433. ViewModel.LoadState(navigationParameter, pageState);
  434. }
  435. }
  436. /// <summary>
  437. /// Preserves state associated with this page in case the application is suspended or the
  438. /// page is discarded from the navigation cache. Values must conform to the serialization
  439. /// requirements of <see cref="SuspensionManager.SessionState"/>.
  440. /// </summary>
  441. /// <param name="pageState">An empty dictionary to be populated with serializable state.</param>
  442. protected virtual void SaveState(Dictionary<String, Object> pageState)
  443. {
  444. if (ViewModel != null)
  445. {
  446. ViewModel.SaveState(pageState);
  447. }
  448. }
  449. #endif
  450. public ViewType ViewType
  451. {
  452. get { return ViewType.Page; }
  453. }
  454. public void Dispose()
  455. {
  456. this.SelfClose();
  457. }
  458. }
  459. public class MVVMControl : UserControl, IView
  460. {
  461. public MVVMControl()
  462. : this(null)
  463. {
  464. }
  465. public MVVMControl(IViewModel viewModel)
  466. {
  467. Unloaded += ViewHelper.ViewUnloadCallBack;
  468. ////////// Unloaded += (_1, _2) => ViewModel = null;
  469. Loaded += async (_1, _2) =>
  470. {
  471. //if (viewModel != null)
  472. //{
  473. // //this.Resources[ViewHelper.DEFAULT_VM_NAME] = viewModel;
  474. // if (!object.ReferenceEquals(ViewModel, viewModel))
  475. // {
  476. // ViewModel = viewModel;
  477. // }
  478. //}
  479. //else
  480. //{
  481. // var solveV = this.GetDefaultViewModel();
  482. // if (solveV != null)
  483. // {
  484. // ViewModel = solveV;
  485. // }
  486. //}
  487. //ViewModel = ViewModel ?? new DefaultViewModel();
  488. await ViewModel.OnBindedViewLoad(this);
  489. };
  490. }
  491. #if !WPF
  492. public object ContentObject
  493. {
  494. get { return Content; }
  495. set { Content = value as FrameworkElement; }
  496. }
  497. #else
  498. public object ContentObject
  499. {
  500. get
  501. {
  502. return Content;
  503. }
  504. set
  505. {
  506. Content = value;
  507. }
  508. }
  509. #endif
  510. #if NETFX_CORE
  511. /// <summary>
  512. /// Populates the page with content passed during navigation. Any saved state is also
  513. /// provided when recreating a page from a prior session.
  514. /// </summary>
  515. /// <param name="navigationParameter">The parameter value passed to
  516. /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
  517. /// </param>
  518. /// <param name="pageState">A dictionary of state preserved by this page during an earlier
  519. /// session. This will be null the first time a page is visited.</param>
  520. protected virtual void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
  521. {
  522. if (ViewModel != null)
  523. {
  524. ViewModel.LoadState(navigationParameter, pageState);
  525. }
  526. }
  527. /// <summary>
  528. /// Preserves state associated with this page in case the application is suspended or the
  529. /// page is discarded from the navigation cache. Values must conform to the serialization
  530. /// requirements of <see cref="SuspensionManager.SessionState"/>.
  531. /// </summary>
  532. /// <param name="pageState">An empty dictionary to be populated with serializable state.</param>
  533. protected virtual void SaveState(Dictionary<String, Object> pageState)
  534. {
  535. if (ViewModel != null)
  536. {
  537. ViewModel.SaveState(pageState);
  538. }
  539. }
  540. #endif
  541. //public IViewModel DesigningViewModel
  542. //{
  543. // get { return (IViewModel)GetValue(DesigningViewModelProperty); }
  544. // set { SetValue(DesigningViewModelProperty, value); }
  545. //}
  546. //// Using a DependencyProperty as the backing store for DesigningViewModel. This enables animation, styling, binding, etc...
  547. //public static readonly DependencyProperty DesigningViewModelProperty =
  548. // DependencyProperty.Register("DesigningViewModel", typeof(IViewModel), typeof(MVVMControl), new PropertyMetadata(null, ViewHelper.DesigningViewModelChangedCallBack));
  549. public IViewModel ViewModel
  550. {
  551. get
  552. {
  553. var vm = GetValue(ViewModelProperty) as IViewModel;
  554. var content = this.GetContentAndCreateIfNull();
  555. if (vm == null)
  556. {
  557. vm = content.DataContext as IViewModel;
  558. SetValue(ViewModelProperty, vm);
  559. }
  560. else
  561. {
  562. IView view = this;
  563. if (!Object.ReferenceEquals(content.DataContext, vm))
  564. {
  565. content.DataContext = vm;
  566. }
  567. }
  568. return vm;
  569. }
  570. set
  571. {
  572. SetValue(ViewModelProperty, value);
  573. var c = this.GetContentAndCreateIfNull();
  574. if (!Object.ReferenceEquals(c.DataContext, value))
  575. {
  576. c.DataContext = value;
  577. }
  578. }
  579. }
  580. // Using a DependencyProperty as the backing store for ViewModel. This enables animation, styling, binding, etc...
  581. public static readonly DependencyProperty ViewModelProperty =
  582. DependencyProperty.Register("ViewModel", typeof(IViewModel), typeof(MVVMControl), new PropertyMetadata(null, ViewHelper.ViewModelChangedCallback));
  583. public ViewType ViewType
  584. {
  585. get { return ViewType.Control; }
  586. }
  587. }
  588. public enum ViewType
  589. {
  590. Page,
  591. Window,
  592. Control
  593. }
  594. public interface IView
  595. {
  596. IViewModel ViewModel { get; set; }
  597. ViewType ViewType { get; }
  598. Object ContentObject { get; set; }
  599. DependencyObject Parent { get; }
  600. }
  601. public interface IView<TViewModel> : IView, IDisposable where TViewModel : IViewModel
  602. {
  603. TViewModel SpecificTypedViewModel { get; set; }
  604. }
  605. public struct ViewModelToViewMapper<TModel>
  606. where TModel : IViewModel
  607. {
  608. public static void MapViewToViewModel<TView>()
  609. {
  610. Func<IViewModel> func;
  611. if (!ViewModelToViewMapperHelper.ViewToVMMapping.TryGetValue(typeof(TView), out func))
  612. {
  613. ViewModelToViewMapperHelper.ViewToVMMapping.Add(typeof(TView), () => (ViewModelLocator<TModel>.Instance.Resolve()));
  614. }
  615. }
  616. #if WPF
  617. public ViewModelToViewMapper<TModel> MapToDefault<TView>(TView instance) where TView : class,IView
  618. {
  619. MapViewToViewModel<TView>();
  620. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(instance);
  621. return this;
  622. }
  623. public ViewModelToViewMapper<TModel> MapTo<TView>(string viewMappingKey, TView instance) where TView : class,IView
  624. {
  625. MapViewToViewModel<TView>();
  626. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(viewMappingKey, instance);
  627. return this;
  628. }
  629. public ViewModelToViewMapper<TModel> MapToDefault<TView>(bool alwaysNew = true) where TView : class,IView
  630. {
  631. MapViewToViewModel<TView>();
  632. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(null, d => (TView)Activator.CreateInstance(typeof(TView), d as object), alwaysNew);
  633. return this;
  634. }
  635. public ViewModelToViewMapper<TModel> MapTo<TView>(string viewMappingKey, bool alwaysNew = true) where TView : class,IView
  636. {
  637. MapViewToViewModel<TView>();
  638. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(viewMappingKey, d => (TView)Activator.CreateInstance(typeof(TView), d as object), alwaysNew);
  639. return this;
  640. }
  641. public ViewModelToViewMapper<TModel> MapToDefault<TView>(Func<TModel, TView> factory, bool alwaysNew = true) where TView : class,IView
  642. {
  643. MapViewToViewModel<TView>();
  644. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(null, d => factory((TModel)d), alwaysNew);
  645. return this;
  646. }
  647. public ViewModelToViewMapper<TModel> MapTo<TView>(string viewMappingKey, Func<TModel, TView> factory, bool alwaysNew = true) where TView : class,IView
  648. {
  649. MapViewToViewModel<TView>();
  650. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(viewMappingKey, d => factory((TModel)d), alwaysNew);
  651. return this;
  652. }
  653. #else
  654. public ViewModelToViewMapper<TModel> MapToDefaultControl<TControl>(TControl instance) where TControl : MVVMControl
  655. {
  656. MapViewToViewModel<TControl>();
  657. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(instance);
  658. return this;
  659. }
  660. public ViewModelToViewMapper<TModel> MapToControl<TControl>(string viewMappingKey, TControl instance) where TControl : MVVMControl
  661. {
  662. MapViewToViewModel<TControl>();
  663. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(viewMappingKey, instance);
  664. return this;
  665. }
  666. public ViewModelToViewMapper<TModel> MapToDefaultControl<TControl>(bool alwaysNew = true) where TControl : MVVMControl
  667. {
  668. MapViewToViewModel<TControl>();
  669. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(null, d => (TControl)Activator.CreateInstance(typeof(TControl), d as object), alwaysNew);
  670. return this;
  671. }
  672. public ViewModelToViewMapper<TModel> MapToControl<TControl>(string viewMappingKey, bool alwaysNew = true) where TControl : MVVMControl
  673. {
  674. MapViewToViewModel<TControl>();
  675. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(viewMappingKey, d => (TControl)Activator.CreateInstance(typeof(TControl), d as object), alwaysNew);
  676. return this;
  677. }
  678. public ViewModelToViewMapper<TModel> MapToDefaultControl<TControl>(Func<TModel, TControl> factory, bool alwaysNew = true) where TControl : MVVMControl
  679. {
  680. MapViewToViewModel<TControl>();
  681. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(null, d => factory((TModel)d), alwaysNew);
  682. return this;
  683. }
  684. public ViewModelToViewMapper<TModel> MapToControl<TControl>(string viewMappingKey, Func<TModel, TControl> factory, bool alwaysNew = true) where TControl : MVVMControl
  685. {
  686. MapViewToViewModel<TControl>();
  687. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(viewMappingKey, d => factory((TModel)d), alwaysNew);
  688. return this;
  689. }
  690. #endif
  691. #if WINDOWS_PHONE_8||WINDOWS_PHONE_7||SILVERLIGHT_5
  692. private static Uri GuessViewUri<TPage>(Uri baseUri) where TPage : MVVMPage
  693. {
  694. MapViewToViewModel<TPage>();
  695. baseUri = baseUri ?? new Uri("/", UriKind.Relative);
  696. if (baseUri.IsAbsoluteUri)
  697. {
  698. var path = Path.Combine(baseUri.LocalPath, typeof(TPage).Name + ".xaml");
  699. UriBuilder ub = new UriBuilder(baseUri);
  700. ub.Path = path;
  701. return ub.Uri;
  702. }
  703. else
  704. {
  705. var path = Path.Combine(baseUri.OriginalString, typeof(TPage).Name + ".xaml");
  706. var pageUri = new Uri(path, UriKind.Relative);
  707. return pageUri;
  708. }
  709. }
  710. public ViewModelToViewMapper<TModel> MapToDefault<TPage>(Uri baseUri = null) where TPage : MVVMPage
  711. {
  712. MapViewToViewModel<TPage>();
  713. var pageUri = GuessViewUri<TPage>(baseUri);
  714. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(
  715. Tuple.Create<Uri, Func<IView>>(pageUri,
  716. () => Activator.CreateInstance(typeof(TPage)) as IView
  717. ));
  718. return this;
  719. }
  720. public ViewModelToViewMapper<TModel> MapTo<TPage>(string viewMappingKey, Uri baseUri = null) where TPage : MVVMPage
  721. {
  722. MapViewToViewModel<TPage>();
  723. var pageUri = GuessViewUri<TPage>(baseUri);
  724. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(Tuple.Create<Uri, Func<IView>>(pageUri,
  725. () => Activator.CreateInstance(typeof(TPage)) as IView
  726. ));
  727. return this;
  728. }
  729. //public ViewModelToViewMapper<TModel> MapToDefault(Uri pageUri)
  730. //{
  731. // ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(pageUri);
  732. // return this;
  733. //}
  734. //public ViewModelToViewMapper<TModel> MapTo(string viewMappingKey, Uri pageUri)
  735. //{
  736. // ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(viewMappingKey, pageUri);
  737. // return this;
  738. //}
  739. #endif
  740. #if NETFX_CORE
  741. public ViewModelToViewMapper<TModel> MapToDefault<TPage>() where TPage : MVVMPage
  742. {
  743. MapViewToViewModel<TPage>();
  744. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(typeof(TPage));
  745. return this;
  746. }
  747. public ViewModelToViewMapper<TModel> MapToDefault<TPage>(string viewMappingKey) where TPage : MVVMPage
  748. {
  749. MapViewToViewModel<TPage>();
  750. ViewModelToViewMapperServiceLocator<TModel>.Instance.Register(viewMappingKey, typeof(TPage));
  751. return this;
  752. }
  753. #endif
  754. }
  755. public static class ViewModelToViewMapperHelper
  756. {
  757. internal static Dictionary<Type, Func<IViewModel>> ViewToVMMapping = new Dictionary<Type, Func<IViewModel>>();
  758. public static IViewModel GetDefaultViewModel(this IView view)
  759. {
  760. Func<IViewModel> func;
  761. var vt = view.GetType();
  762. if (ViewModelToViewMapperHelper.ViewToVMMapping.TryGetValue(vt, out func))
  763. {
  764. return func();
  765. }
  766. return null;
  767. }
  768. public static ViewModelToViewMapper<TViewModel> GetViewMapper<TViewModel>(this MVVMSidekick.Services.ServiceLocatorEntryStruct<TViewModel> vmRegisterEntry)
  769. where TViewModel : IViewModel
  770. {
  771. return new ViewModelToViewMapper<TViewModel>();
  772. }
  773. }
  774. public class ViewModelToViewMapperServiceLocator<TViewModel> : MVVMSidekick.Services.TypeSpecifiedServiceLocatorBase<ViewModelToViewMapperServiceLocator<TViewModel>, object>
  775. {
  776. static ViewModelToViewMapperServiceLocator()
  777. {
  778. Instance = new ViewModelToViewMapperServiceLocator<TViewModel>();
  779. }
  780. public static ViewModelToViewMapperServiceLocator<TViewModel> Instance { get; set; }
  781. }
  782. public class ViewModelLocator<TViewModel> : MVVMSidekick.Services.TypeSpecifiedServiceLocatorBase<ViewModelLocator<TViewModel>, TViewModel>
  783. where TViewModel : IViewModel
  784. {
  785. static ViewModelLocator()
  786. {
  787. Instance = new ViewModelLocator<TViewModel>();
  788. }
  789. public static ViewModelLocator<TViewModel> Instance { get; set; }
  790. }
  791. public class Stage : DependencyObject
  792. {
  793. public Stage(FrameworkElement target, string beaconKey, StageManager navigator)
  794. {
  795. Target = target;
  796. _navigator = navigator;
  797. BeaconKey = beaconKey;
  798. //SetupNavigateFrame();
  799. }
  800. StageManager _navigator;
  801. FrameworkElement _target;
  802. public Frame Frame
  803. {
  804. get { return (Frame)GetValue(FrameProperty); }
  805. private set { SetValue(FrameProperty, value); }
  806. }
  807. // Using a DependencyProperty as the backing store for Frame. This enables animation, styling, binding, etc...
  808. public static readonly DependencyProperty FrameProperty =
  809. DependencyProperty.Register("Frame", typeof(Frame), typeof(Stage), new PropertyMetadata(null));
  810. public FrameworkElement Target
  811. {
  812. get { return _target; }
  813. private set
  814. {
  815. _target = value;
  816. Frame = _target as Frame;
  817. }
  818. }
  819. #if WPF
  820. public bool IsGoForwardSupported
  821. {
  822. get
  823. {
  824. return Frame != null;
  825. }
  826. }
  827. public bool CanGoForward
  828. {
  829. get
  830. {
  831. return IsGoForwardSupported ? Frame.CanGoForward : false;
  832. }
  833. }
  834. #else
  835. public bool IsGoForwardSupported
  836. {
  837. get
  838. {
  839. return false;
  840. }
  841. }
  842. public bool CanGoForward
  843. {
  844. get
  845. {
  846. return false;
  847. }
  848. }
  849. #endif
  850. public bool IsGoBackSupported
  851. {
  852. get
  853. {
  854. return Frame != null;
  855. }
  856. }
  857. public bool CanGoBack
  858. {
  859. get
  860. {
  861. return IsGoBackSupported ? Frame.CanGoBack : false;
  862. }
  863. }
  864. public string BeaconKey
  865. {
  866. get { return (string)GetValue(BeaconKeyProperty); }
  867. private set { SetValue(BeaconKeyProperty, value); }
  868. }
  869. // Using a DependencyProperty as the backing store for BeaconKey. This enables animation, styling, binding, etc...
  870. public static readonly DependencyProperty BeaconKeyProperty =
  871. DependencyProperty.Register("BeaconKey", typeof(string), typeof(Stage), new PropertyMetadata(""));
  872. #if WPF
  873. private static IView InternalLocateViewIfNotSet<TTarget>(TTarget targetViewModel, string viewMappingKey, IView view) where TTarget : class, IViewModel
  874. {
  875. if (targetViewModel != null && targetViewModel.StageManager != null)
  876. {
  877. view = targetViewModel.StageManager.CurrentBindingView as IView;
  878. }
  879. view = view ?? ViewModelToViewMapperServiceLocator<TTarget>.Instance.Resolve(viewMappingKey, targetViewModel) as IView;
  880. return view;
  881. }
  882. public async Task Show<TTarget>(TTarget targetViewModel = null, string viewMappingKey = null)
  883. where TTarget : class,IViewModel
  884. {
  885. IView view = null;
  886. view = InternalLocateViewIfNotSet<TTarget>(targetViewModel, viewMappingKey, view);
  887. targetViewModel = targetViewModel ?? view.ViewModel as TTarget;
  888. if (view.ViewType == ViewType.Page)
  889. {
  890. var mvpg = view as MVVMPage;
  891. mvpg.Frame = Frame;
  892. }
  893. SetVMAfterLoad(targetViewModel, view);
  894. InternalShowView(view, Target, _navigator.CurrentBindingView.ViewModel);
  895. await targetViewModel.WaitForClose();
  896. }
  897. public async Task<TResult> Show<TTarget, TResult>(TTarget targetViewModel = null, string viewMappingKey = null)
  898. where TTarget : class,IViewModel<TResult>
  899. {
  900. IView view = null;
  901. view = InternalLocateViewIfNotSet<TTarget>(targetViewModel, viewMappingKey, view);
  902. targetViewModel = targetViewModel ?? view.ViewModel as TTarget;
  903. if (view.ViewType == ViewType.Page)
  904. {
  905. var mvpg = view as MVVMPage;
  906. mvpg.Frame = Frame;
  907. }
  908. SetVMAfterLoad(targetViewModel, view);
  909. InternalShowView(view, Target, _navigator.CurrentBindingView.ViewModel);
  910. return await targetViewModel.WaitForCloseWithResult();
  911. }
  912. public async Task<ShowAwaitableResult<TTarget>> ShowAndGetViewModel<TTarget>(TTarget targetViewModel = null, string viewMappingKey = null)
  913. where TTarget : class,IViewModel
  914. {
  915. IView view = null;
  916. view = InternalLocateViewIfNotSet<TTarget>(targetViewModel, viewMappingKey, view);
  917. targetViewModel = targetViewModel ?? view.ViewModel as TTarget;
  918. if (view.ViewType == ViewType.Page)
  919. {
  920. var mvpg = view as MVVMPage;
  921. mvpg.Frame = Frame;
  922. }
  923. SetVMAfterLoad(targetViewModel, view);
  924. InternalShowView(view, Target, _navigator.CurrentBindingView.ViewModel);
  925. return await TaskExHelper.FromResult(new ShowAwaitableResult<TTarget> { Closing = targetViewModel.WaitForClose(), ViewModel = targetViewModel });
  926. }
  927. #endif
  928. #if SILVERLIGHT_5||WINDOWS_PHONE_7||WINDOWS_PHONE_8
  929. internal Dictionary<string, IViewModel> NavigateRequestContexts
  930. {
  931. get
  932. {
  933. return GetNavigateRequestContexts(Frame);
  934. }
  935. set
  936. {
  937. SetNavigateRequestContexts(Frame, value);
  938. }
  939. }
  940. public static Dictionary<string, IViewModel> GetNavigateRequestContexts(DependencyObject obj)
  941. {
  942. return (Dictionary<string, IViewModel>)obj.GetValue(NavigateRequestContextsProperty);
  943. }
  944. public static void SetNavigateRequestContexts(DependencyObject obj, Dictionary<string, IViewModel> value)
  945. {
  946. obj.SetValue(NavigateRequestContextsProperty, value);
  947. }
  948. // Using a DependencyProperty as the backing store for NavigateRequestContexts. This enables animation, styling, binding, etc...
  949. public static readonly DependencyProperty NavigateRequestContextsProperty =
  950. DependencyProperty.RegisterAttached("NavigateRequestContexts", typeof(Dictionary<string, IViewModel>), typeof(Stage), new PropertyMetadata(new Dictionary<string, IViewModel>()));
  951. public async Task Show<TTarget>(TTarget targetViewModel = null, string viewMappingKey = null)
  952. where TTarget : class,IViewModel
  953. {
  954. var item = ViewModelToViewMapperServiceLocator<TTarget>.Instance.Resolve(viewMappingKey, targetViewModel);
  955. Tuple<Uri, Func<IView>> uriData;
  956. uriData = item as Tuple<Uri, Func<IView>>;
  957. if (uriData != null) //only sl like page Can be registered as uri
  958. {
  959. Frame frame;
  960. if ((frame = Target as Frame) != null)
  961. {
  962. targetViewModel = await FrameNavigate<TTarget>(targetViewModel, uriData, frame);
  963. await targetViewModel.WaitForClose();
  964. return;
  965. }
  966. else
  967. {
  968. item = uriData.Item2();
  969. }
  970. }
  971. IView view = item as IView;
  972. targetViewModel = targetViewModel ?? view.ViewModel as TTarget;
  973. SetVMAfterLoad(targetViewModel, view);
  974. InternalShowView(view, Target, _navigator.CurrentBindingView.ViewModel);
  975. await targetViewModel.WaitForClose();
  976. }
  977. public async Task<TResult> Show<TTarget, TResult>(TTarget targetViewModel = null, string viewMappingKey = null)
  978. where TTarget : class,IViewModel<TResult>
  979. {
  980. var item = ViewModelToViewMapperServiceLocator<TTarget>.Instance.Resolve(viewMappingKey, targetViewModel);
  981. Tuple<Uri, Func<IView>> uriData;
  982. if ((uriData = item as Tuple<Uri, Func<IView>>) != null) //only sl like page Can be registered as uri
  983. {
  984. Frame frame;
  985. if ((frame = Target as Frame) != null)
  986. {
  987. targetViewModel = await FrameNavigate<TTarget>(targetViewModel, uriData, frame);
  988. return await targetViewModel.WaitForCloseWithResult();
  989. }
  990. else
  991. {
  992. item = uriData.Item2();
  993. }
  994. }
  995. IView view = item as IView;
  996. targetViewModel = targetViewModel ?? view.ViewModel as TTarget;
  997. SetVMAfterLoad(targetViewModel, view);
  998. InternalShowView(view, Target, _navigator.CurrentBindingView.ViewModel);
  999. return await targetViewModel.WaitForCloseWithResult();
  1000. }
  1001. private async Task<TTarget> FrameNavigate<TTarget>(TTarget targetViewModel, Tuple<Uri, Func<IView>> uriData, Frame frame) where TTarget : class,IViewModel
  1002. {
  1003. var t = new TaskCompletionSource<object>();
  1004. var guid = Guid.NewGuid();
  1005. var newUriWithParameter = new Uri(uriData.Item1.ToString() + "?CallBackGuid=" + guid.ToString(), UriKind.Relative);
  1006. var dis = EventRouting.EventRouter.Instance.GetEventObject<System.Windows.Navigation.NavigationEventArgs>()
  1007. .Where(e =>
  1008. e.EventArgs.Uri == newUriWithParameter)
  1009. .Subscribe(e =>
  1010. {
  1011. var key = newUriWithParameter.ToString();
  1012. lock (NavigateRequestContexts)
  1013. {
  1014. IViewModel vm = null;
  1015. if (NavigateRequestContexts.TryGetValue(key, out vm))
  1016. {
  1017. targetViewModel = vm as TTarget;
  1018. }
  1019. var page = e.Sender as MVVMPage;
  1020. if (targetViewModel != null)
  1021. {
  1022. page.ViewModel = targetViewModel;
  1023. }
  1024. else
  1025. {
  1026. var solveV = page.GetDefaultViewModel();
  1027. if (solveV != null)
  1028. {
  1029. page.ViewModel = solveV;
  1030. }
  1031. }
  1032. targetViewModel = (TTarget)page.ViewModel;
  1033. NavigateRequestContexts[key] = targetViewModel;
  1034. }
  1035. if (!t.Task.IsCompleted)
  1036. {
  1037. targetViewModel.AddDisposeAction(() =>
  1038. {
  1039. lock (NavigateRequestContexts)
  1040. {
  1041. NavigateRequestContexts.Remove(key);
  1042. }
  1043. });
  1044. t.SetResult(null);
  1045. }
  1046. }
  1047. );
  1048. frame.Navigate(newUriWithParameter);
  1049. await t.Task;
  1050. dis.DisposeWith(targetViewModel);
  1051. return targetViewModel;
  1052. }
  1053. public async Task<ShowAwaitableResult<TTarget>> ShowAndGetViewModel<TTarget>(TTarget targetViewModel = null, string viewMappingKey = null)
  1054. where TTarget : class,IViewModel
  1055. {
  1056. var item = ViewModelToViewMapperServiceLocator<TTarget>.Instance.Resolve(viewMappingKey, targetViewModel);
  1057. Tuple<Uri, Func<IView>> uriData;
  1058. if ((uriData = item as Tuple<Uri, Func<IView>>) != null) //only sl like page Can be registered as uri
  1059. {
  1060. Frame frame;
  1061. if ((frame = Target as Frame) != null)
  1062. {
  1063. targetViewModel = await FrameNavigate<TTarget>(targetViewModel, uriData, frame);
  1064. return new ShowAwaitableResult<TTarget> { Closing = targetViewModel.WaitForClose(), ViewModel = targetViewModel };
  1065. }
  1066. else
  1067. {
  1068. item = uriData.Item2();
  1069. }
  1070. }
  1071. IView view = item as IView;
  1072. targetViewModel = targetViewModel ?? view.ViewModel as TTarget;
  1073. SetVMAfterLoad(targetViewModel, view);
  1074. InternalShowView(view, Target, _navigator.CurrentBindingView.ViewModel);
  1075. var tr = targetViewModel.WaitForClose();
  1076. return new ShowAwaitableResult<TTarget> { Closing = targetViewModel.WaitForClose(), ViewModel = targetViewModel };
  1077. }
  1078. #endif
  1079. private static void SetVMAfterLoad<TTarget>(TTarget targetViewModel, IView view) where TTarget : class, IViewModel
  1080. {
  1081. if (view == null)
  1082. {
  1083. throw new InvalidOperationException(
  1084. string.Format(@"
  1085. Cannot find ANY mapping from View Model [{0}] to ANY View.
  1086. Please check startup function of this mapping is well configured and be proper called while application starting",
  1087. targetViewModel.GetType().ToString()));
  1088. }
  1089. if (view.ViewType == ViewType.Page)
  1090. {
  1091. var pg = view as MVVMPage;
  1092. pg.ViewModel = targetViewModel;
  1093. }
  1094. view.ViewModel = targetViewModel;
  1095. //var frview = view as FrameworkElement;
  1096. //RoutedEventHandler loadEvent = null;
  1097. //loadEvent = (_1, _2) =>
  1098. //{
  1099. // view.ViewModel = targetViewModel;
  1100. // frview.Loaded -= loadEvent;
  1101. //};
  1102. //frview.Loaded += loadEvent;
  1103. }
  1104. #if NETFX_CORE
  1105. public async Task Show<TTarget>(TTarget targetViewModel = null, string viewMappingKey = null)
  1106. where TTarget : class,IViewModel
  1107. {
  1108. var item = ViewModelToViewMapperServiceLocator<TTarget>.Instance.Resolve(viewMappingKey, targetViewModel);
  1109. Type type;
  1110. if ((type = item as Type) != null) //only MVVMPage Can be registered as Type
  1111. {
  1112. var frame = Target as Frame;
  1113. if (frame != null)
  1114. {
  1115. targetViewModel = await FrameNavigate<TTarget>(targetViewModel, type, frame);
  1116. await targetViewModel.WaitForClose();
  1117. return;
  1118. }
  1119. }
  1120. IView view = item as IView;
  1121. targetViewModel = targetViewModel ?? view.ViewModel as TTarget;
  1122. SetVMAfterLoad(targetViewModel, view);
  1123. InternalShowView(view, Target, _navigator.CurrentBindingView.ViewModel);
  1124. await targetViewModel.WaitForClose();
  1125. }
  1126. private static async Task<TTarget> FrameNavigate<TTarget>(TTarget targetViewModel, Type type, Windows.UI.Xaml.Controls.Frame frame) where TTarget : class, IViewModel
  1127. {
  1128. var parameter = new StageNavigationContext<TTarget>() { ViewModel = targetViewModel };
  1129. var t = new TaskCompletionSource<object>();
  1130. var dip = EventRouting.EventRouter.Instance
  1131. .GetEventObject<NavigationEventArgs>()
  1132. .Where(e =>
  1133. object.ReferenceEquals(e.EventArgs.Parameter, parameter))
  1134. .Subscribe(e =>
  1135. {
  1136. var page = e.Sender as MVVMPage;
  1137. if (parameter.ViewModel != null)
  1138. {
  1139. page.ViewModel = parameter.ViewModel;
  1140. }
  1141. else
  1142. {
  1143. var solveV = page.GetDefaultViewModel();
  1144. if (solveV != null)
  1145. {
  1146. targetViewModel = parameter.ViewModel = (TTarget)solveV;
  1147. }
  1148. }
  1149. if (targetViewModel == null)
  1150. {
  1151. targetViewModel = (TTarget)page.ViewModel;
  1152. }
  1153. parameter.ViewModel = targetViewModel;
  1154. if (!t.Task.IsCompleted)
  1155. {
  1156. t.SetResult(null); ;
  1157. }
  1158. });
  1159. frame.Navigate(type, parameter);
  1160. await t.Task;
  1161. dip.DisposeWith(targetViewModel);
  1162. return targetViewModel;
  1163. }
  1164. class StageNavigationContext<T> where T : IViewModel
  1165. {
  1166. public T ViewModel { get; set; }
  1167. }
  1168. public async Task<TResult> Show<TTarget, TResult>(TTarget targetViewModel = null, string viewMappingKey = null)
  1169. where TTarget : class,IViewModel<TResult>
  1170. {
  1171. var item = ViewModelToViewMapperServiceLocator<TTarget>.Instance.Resolve(viewMappingKey, targetViewModel);
  1172. Type type;
  1173. if ((type = item as Type) != null) //only MVVMPage Can be registered as Type
  1174. {
  1175. Frame frame;
  1176. if ((frame = Target as Frame) != null)
  1177. {
  1178. targetViewModel = await FrameNavigate<TTarget>(targetViewModel, type, frame);
  1179. return await targetViewModel.WaitForCloseWithResult();
  1180. }
  1181. }
  1182. IView view = item as IView;
  1183. targetViewModel = targetViewModel ?? view.ViewModel as TTarget;
  1184. SetVMAfterLoad(targetViewModel, view);
  1185. InternalShowView(view, Target, _navigator.CurrentBindingView.ViewModel);
  1186. return await targetViewModel.WaitForCloseWithResult();
  1187. }
  1188. public async Task<ShowAwaitableResult<TTarget>> ShowAndGetViewModel<TTarget>(TTarget targetViewModel = null, string viewMappingKey = null)
  1189. where TTarget : class,IViewModel
  1190. {
  1191. var item = ViewModelToViewMapperServiceLocator<TTarget>.Instance.Resolve(viewMappingKey, targetViewModel);
  1192. Type type;
  1193. if ((type = item as Type) != null) //only MVVMPage Can be registered as Type
  1194. {
  1195. Frame frame;
  1196. if ((frame = Target as Frame) != null)
  1197. {
  1198. targetViewModel = await FrameNavigate<TTarget>(targetViewModel, type, frame);
  1199. return new ShowAwaitableResult<TTarget>
  1200. {
  1201. Closing = targetViewModel.WaitForClose(),
  1202. ViewModel = targetViewModel
  1203. };
  1204. }
  1205. }
  1206. IView view = item as IView;
  1207. targetViewModel = targetViewModel ?? view.ViewModel as TTarget;
  1208. SetVMAfterLoad(targetViewModel, view);
  1209. InternalShowView(view, Target, _navigator.CurrentBindingView.ViewModel);
  1210. var tr = targetViewModel.WaitForClose();
  1211. return new ShowAwaitableResult<TTarget> { Closing = tr, ViewModel = targetViewModel };
  1212. }
  1213. #endif
  1214. private void InternalShowView(IView view, FrameworkElement target, IViewModel sourceVM)
  1215. {
  1216. if (view is UserControl || view is Page)
  1217. {
  1218. if (target is ContentControl)
  1219. {
  1220. var targetCControl = target as ContentControl;
  1221. var oldcontent = targetCControl.Content as IDisposable;
  1222. targetCControl.Content = view;
  1223. }
  1224. else if (target is Panel)
  1225. {
  1226. var targetPanelControl = target as Panel;
  1227. targetPanelControl.Children.Add(view as UIElement);
  1228. }
  1229. else
  1230. {
  1231. throw new InvalidOperationException(string.Format("This view {0} is not support show in {1} ", view.GetType(), target.GetType()));
  1232. }
  1233. }
  1234. #if WPF
  1235. else if (view is Window)
  1236. {
  1237. var viewWindow = view as Window;
  1238. viewWindow.HorizontalAlignment = HorizontalAlignment.Center;
  1239. viewWindow.VerticalAlignment = VerticalAlignment.Center;
  1240. var targetWindow = target as Window;
  1241. if (targetWindow == null)
  1242. {
  1243. targetWindow = sourceVM.StageManager.CurrentBindingView as Window;
  1244. }
  1245. viewWindow.Owner = targetWindow;
  1246. viewWindow.Show();
  1247. }
  1248. #endif
  1249. }
  1250. }
  1251. /// <summary>
  1252. /// The abstract for frame/contentcontrol. VM can access this class to Show other vm and vm's mapped view.
  1253. /// </summary>
  1254. public class StageManager : DependencyObject
  1255. {
  1256. static StageManager()
  1257. {
  1258. NavigatorBeaconsKey = "NavigatorBeaconsKey";
  1259. }
  1260. public StageManager(IViewModel viewModel)
  1261. {
  1262. _ViewModel = viewModel;
  1263. }
  1264. IViewModel _ViewModel;
  1265. /// <summary>
  1266. /// This Key is a prefix for register keys.
  1267. /// The stage registeration store the String-Element-Mapping in view's Resource Dictionary(Resource property).
  1268. /// This can help not to overwrite the resources already defined.
  1269. /// </summary>
  1270. public static string NavigatorBeaconsKey;
  1271. IView _CurrentBindingView;
  1272. /// <summary>
  1273. /// Get the currently binded view of this stagemanager. A stagemanager is for a certain view. If viewmodel is not binded to a view, the whole thing cannot work.
  1274. /// </summary>
  1275. public IView CurrentBindingView
  1276. {
  1277. get
  1278. {
  1279. return _CurrentBindingView;
  1280. }
  1281. internal set
  1282. {
  1283. _CurrentBindingView = value;
  1284. }
  1285. }
  1286. public void InitParent(Func<DependencyObject> parentLocator)
  1287. {
  1288. _parentLocator = parentLocator;
  1289. DefaultStage = this[""];
  1290. }
  1291. Func<DependencyObject> _parentLocator;
  1292. #region Attached Property
  1293. #if WPF
  1294. [AttachedPropertyBrowsableForType(typeof(ContentControl))]
  1295. [AttachedPropertyBrowsableForType(typeof(Frame))]
  1296. [AttachedPropertyBrowsableForType(typeof(Window))]
  1297. #endif
  1298. public static string GetBeacon(DependencyObject obj)
  1299. {
  1300. return (string)obj.GetValue(BeaconProperty);
  1301. }
  1302. #if WPF
  1303. [AttachedPropertyBrowsableForType(typeof(ContentControl))]
  1304. [AttachedPropertyBrowsableForType(typeof(Frame))]
  1305. [AttachedPropertyBrowsableForType(typeof(Window))]
  1306. #endif
  1307. public static void SetBeacon(DependencyObject obj, string value)
  1308. {
  1309. obj.SetValue(BeaconProperty, value);
  1310. }
  1311. public static readonly DependencyProperty BeaconProperty =
  1312. DependencyProperty.RegisterAttached("Beacon", typeof(string), typeof(StageManager), new PropertyMetadata(null,
  1313. (o, p) =>
  1314. {
  1315. var name = (p.NewValue as string);
  1316. var target = o as FrameworkElement;
  1317. target.Loaded +=
  1318. (_1, _2)
  1319. =>
  1320. {
  1321. StageManager.RegisterTargetBeacon(name, target);
  1322. };
  1323. }
  1324. ));
  1325. #endregion
  1326. internal FrameworkElement LocateTargetContainer(IView view, ref string targetContainerName, IViewModel sourceVM)
  1327. {
  1328. targetContainerName = targetContainerName ?? "";
  1329. var viewele = view as FrameworkElement;
  1330. FrameworkElement target = null;
  1331. var dic = GetOrCreateBeacons(sourceVM.StageManager.CurrentBindingView as FrameworkElement);
  1332. dic.TryGetValue(targetContainerName, out target);
  1333. if (target == null)
  1334. {
  1335. target = _parentLocator() as FrameworkElement;
  1336. }
  1337. if (target == null)
  1338. {
  1339. var vieweleCt = viewele as ContentControl;
  1340. if (vieweleCt != null)
  1341. {
  1342. target = vieweleCt.Content as FrameworkElement;
  1343. }
  1344. }
  1345. return target;
  1346. }
  1347. private static Dictionary<string, FrameworkElement> GetOrCreateBeacons(FrameworkElement view)
  1348. {
  1349. Dictionary<string, FrameworkElement> dic;
  1350. #if NETFX_CORE
  1351. if (!view.Resources.ContainsKey(NavigatorBeaconsKey))
  1352. #else
  1353. if (!view.Resources.Contains(NavigatorBeaconsKey))
  1354. #endif
  1355. {
  1356. dic = new Dictionary<string, FrameworkElement>();
  1357. view.Resources.Add(NavigatorBeaconsKey, dic);
  1358. }
  1359. else
  1360. dic = view.Resources[NavigatorBeaconsKey] as Dictionary<string, FrameworkElement>;
  1361. return dic;
  1362. }
  1363. public static void RegisterTargetBeacon(string name, FrameworkElement target)
  1364. {
  1365. var view = LocateIView(target);
  1366. var beacons = GetOrCreateBeacons(view);
  1367. beacons[name] = target;
  1368. }
  1369. private static FrameworkElement LocateIView(FrameworkElement target)
  1370. {
  1371. var view = target;
  1372. while (view != null)
  1373. {
  1374. if (view is IView)
  1375. {
  1376. break;
  1377. }
  1378. view = view.Parent as FrameworkElement;
  1379. }
  1380. return view;
  1381. }
  1382. public Stage DefaultStage
  1383. {
  1384. get { return (Stage)GetValue(DefaultTargetProperty); }
  1385. set { SetValue(DefaultTargetProperty, value); }
  1386. }
  1387. // Using a DependencyProperty as the backing store for DefaultTarget. This enables animation, styling, binding, etc...
  1388. public static readonly DependencyProperty DefaultTargetProperty =
  1389. DependencyProperty.Register("DefaultTarget", typeof(Stage), typeof(StageManager), new PropertyMetadata(null));
  1390. public Stage this[string beaconKey]
  1391. {
  1392. get
  1393. {
  1394. var fr = LocateTargetContainer(CurrentBindingView, ref beaconKey, _ViewModel);
  1395. if (fr != null)
  1396. {
  1397. return new Stage(fr, beaconKey, this);
  1398. }
  1399. else
  1400. return null;
  1401. }
  1402. }
  1403. }
  1404. public class PropertyBridge : FrameworkElement
  1405. {
  1406. public PropertyBridge()
  1407. {
  1408. base.Width = 0;
  1409. base.Height = 0;
  1410. base.Visibility = Visibility.Collapsed;
  1411. }
  1412. public object Source
  1413. {
  1414. private get { return (object)GetValue(SourceProperty); }
  1415. set { SetValue(SourceProperty, value); }
  1416. }
  1417. // Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
  1418. public static readonly DependencyProperty SourceProperty =
  1419. DependencyProperty.Register("Source", typeof(object), typeof(PropertyBridge), new PropertyMetadata(null,
  1420. (o, a) =>
  1421. {
  1422. var pb = o as PropertyBridge;
  1423. if (pb != null)
  1424. {
  1425. pb.Target = a.NewValue;
  1426. }
  1427. }
  1428. ));
  1429. public object Target
  1430. {
  1431. get { return (object)GetValue(TargetProperty); }
  1432. set { SetValue(TargetProperty, value); }
  1433. }
  1434. // Using a DependencyProperty as the backing store for Target. This enables animation, styling, binding, etc...
  1435. public static readonly DependencyProperty

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