PageRenderTime 59ms CodeModel.GetById 27ms RepoModel.GetById 1ms 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
  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 TargetProperty =
  1436. DependencyProperty.Register("Target", typeof(object), typeof(PropertyBridge), new PropertyMetadata(null));
  1437. }
  1438. }
  1439. }