如何使用WinRT Caliburn.Micro将参数传递给导航视图模型?
我正在使用WinRT Caliburn.Micro开发Windowsapp store应用游戏,我依赖于导航框架。
我有游戏设置(定义玩家)和实际游戏的视图模型。 当从设置导航到游戏时,我想将玩家的集合传递给游戏视图模型。 我怎样才能做到这一点?
原理上,我的视图模型目前看起来像这样:
public class SetupGameViewModel : NavigationViewModelBase { public SetupGameViewModel(INavigationService ns) : base(ns) { } public IObservableCollection Players { get; set; } public void StartGame() { // This is as far as I've got... base.NavigationService.NavigateToViewModel(); // How can I pass the Players collection from here to the GameViewModel? } } public class GameViewModel : NavigationViewModelBase { public GameViewModel(INavigationService ns) : base(ns) { } public ScoreBoardViewModel ScoreBoard { get; private set; } public void InitializeScoreBoard(IEnumerable players) { ScoreBoard = new ScoreBoardViewModel(players); } }
理想情况下,我想从GameViewModel
构造函数中调用InitializeScoreBoard
,但据我所知,不可能将SetupGameViewModel.Players
集合传递给SetupGameViewModel.Players
构造函数。
INavigationService.NavigateToViewModel
(扩展)方法可选地接受[object] parameter
参数,但此参数似乎未到达导航到的视图模型构造函数。 我无法弄清楚如何从SetupGameViewModel.StartGame
方法显式调用SetupGameViewModel.StartGame
方法,因为SetupGameViewModel.StartGame
尚未在此阶段初始化。
好吧,只是把它放在那里, Caliburn.Micro
为WP8和WinRT统一导航:
NavigationService.UriFor().WithParam(x => x.TargetProperty, ValueToPass).Navigate();
您可以将WithParam
到多个参数。 现在有一些限制,并非所有类型都经过,我不太清楚究竟是什么原因,但它有一些关于导航如何在WinRT中工作的事情。 在Caliburn.Micro
讨论部分提到了它。
无论如何,你可以这样导航。 不要依赖于构造函数,它将调用OnInitialize
和OnActivate
。 所以,只是把它切成例子:
NavigationService.UriFor().WithParam(x => x.Id, SelectedDetailsId).Navigate();
然后在DetailsViewModel
:
protected override void OnInitialize() { //Here you'll have Id property initialized to 'SelectedDetailsId' from the previous screen. }
所以,在纯理论中,你可以这样做:
NavigationService.UriFor().WithParam(x => x.Players, Players).Navigate();
在设置中然后:
public class GameViewModel { public GameViewModel(INavigationService ns) : base(ns) { //It would probably be good to initialize Players here to avoid null } public ScoreBoardViewModel ScoreBoard { get; private set; } public IObservableCollection Players {get;set;} protected void OnInitialize() { //If everything goes as expected, Players should be populated now. ScoreBoard = new ScoreBoard(Players); } }
但在实践中,我并不认为传递像这样的复杂结构(类等的集合)会起作用。
更原始的类型工作得很好( int
, string
, DateTime
等,但是例如URI
对我来说不起作用,总是为null
),所以最糟糕的情况/解决方法是,例如,将Players
列表序列化为temp导航前的文件,并将文件路径作为字符串传递给GameViewModel中的反序列化。
有人参与漫游SO的框架,他们可能会给你更多有价值的见解。
最后,我通过实现临时事件处理程序解决了这个问题。 事实certificate,我可以使用NavigateToViewModel
重载来传递播放器集合。
从Caliburn Micro论坛和MSDN文档中我得到的印象是这种方法只能保证适用于“原始”类型,尽管在我的场景中我到目前为止还没有发现任何问题。
我的SetupGameViewModel.StartGame
方法现在实现如下:
public void StartGame() { base.NavigationService.Navigated += NavigationServiceOnNavigated; base.NavigationService.NavigateToViewModel(Players); base.NavigationService.Navigated -= NavigationServiceOnNavigated; }
临时附加的NavigationServiceOnNavigated
事件处理程序实现如下:
private static void NavigationServiceOnNavigated(object sender, NavigationEventArgs args) { FrameworkElement view; GameViewModel gameViewModel; if ((view = args.Content as FrameworkElement) == null || (gameViewModel = view.DataContext as GameViewModel) == null) return; gameViewModel.InitializeScoreBoard(args.Parameter as IEnumerable); }
不是我真正想要的干净解决方案,但至少它似乎有效。
在Win Store应用程序中,您可以在NavigationService的帮助下在ViewModel之间移交复杂对象。 仅在Silverlight应用程序中,您才被限制为必须可序列化为字符串的对象。 Win Store应用程序中不存在此限制。
在你的情况下,类似下面的东西应该工作。 在StartGame()中,NavigationService用于调用GameViewModel。 播放器列表作为简单参数移交。 按照惯例,此参数将分配给目标ViewModel的属性Parameter。
public class SetupGameViewModel : Screen { private readonly INavigationService _navigationService; public MainPageViewModel(INavigationService navigationService) { _navigationService = navigationService; } public IObservableCollection Players { get; set; } public void StartGame() { _navigationService.NavigateToViewModel(Players); } ... } public class GameViewModel : Screen { private IObservableCollection _parameter; public IObservableCollection Parameter { get { return _parameter; } set { if (value.Equals(_parameter)) return; _parameter = value; NotifyOfPropertyChange(() => Parameter); } } protected override void OnActivate() { // do something with the player list // ... } ... }
有关此主题的更多详细信息,请访问: http : //wp.qmatteoq.com/using-caliburn-micro-with-universal-windows-app-navigation/