[英]How to pass parameter to navigated view model with WinRT Caliburn.Micro?
我正在使用WinRT Caliburn.Micro開發Windows應用商店應用游戲,我依賴於導航框架。
我有游戲設置(定義玩家)和實際游戲的視圖模型。 當從設置導航到游戲時,我想將玩家的集合傳遞給游戲視圖模型。 我怎樣才能做到這一點?
原理上,我的視圖模型目前看起來像這樣:
public class SetupGameViewModel : NavigationViewModelBase
{
public SetupGameViewModel(INavigationService ns) : base(ns) { }
public IObservableCollection<Player> Players { get; set; }
public void StartGame()
{
// This is as far as I've got...
base.NavigationService.NavigateToViewModel<GameViewModel>();
// 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<Player> players)
{
ScoreBoard = new ScoreBoardViewModel(players);
}
}
理想情況下,我想打電話給InitializeScoreBoard
從內GameViewModel
構造,但據我已經能夠告訴它是不可能將通過SetupGameViewModel.Players
收集到GameViewModel
構造。
INavigationService.NavigateToViewModel<T>
(擴展)方法可選地接受[object] parameter
參數,但此參數似乎沒有到達導航到的視圖模型構造函數。 我無法弄清楚如何顯式調用GameViewModel.InitializeScoreBoard
從方法SetupGameViewModel.StartGame
方法,因為相關的GameViewModel
尚未在這個階段初始化。
好吧,只是把它放在那里, Caliburn.Micro
為WP8和WinRT統一導航:
NavigationService.UriFor<TargetViewModel>().WithParam(x => x.TargetProperty, ValueToPass).Navigate();
您可以將WithParam
到多個參數。 現在有一些限制,並非所有類型都經過,我不太清楚究竟是什么原因,但它有一些關於導航如何在WinRT中工作的事情。 在Caliburn.Micro
討論部分的某處提到了它。
無論如何,你可以這樣導航。 不要依賴於構造函數,它將調用OnInitialize
和OnActivate
。 所以,只是把它切成例子:
NavigationService.UriFor<DetailsViewModel>().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<GameViewModel>().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<Player> 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的框架,他們可能會給你更多有價值的見解。
最后,我通過實現臨時事件處理程序解決了這個問題。 事實證明,我可以使用NavigateToViewModel<T>(object)
重載來傳遞播放器集合。
從Caliburn Micro論壇和MSDN文檔中我得到的印象是這種方法只能保證適用於“原始”類型,盡管在我的場景中我到目前為止還沒有發現任何問題。
我的SetupGameViewModel.StartGame
方法現在實現如下:
public void StartGame()
{
base.NavigationService.Navigated += NavigationServiceOnNavigated;
base.NavigationService.NavigateToViewModel<GameViewModel>(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<Player>);
}
不是我真正想要的干凈解決方案,但至少它似乎有效。
在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<Player> Players { get; set; }
public void StartGame()
{
_navigationService.NavigateToViewModel<GameViewModel>(Players);
}
...
}
public class GameViewModel : Screen
{
private IObservableCollection<Player> _parameter;
public IObservableCollection<Player> 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/
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.