C# 如何使用WinRT Caliburn.Micro将参数传递到导航视图模型?
我正在使用WinRT Caliburn.Micro开发一个Windows应用商店应用程序游戏,我依赖于导航框架 我有游戏设置(定义玩家)和实际游戏的视图模型。当从设置导航到游戏时,我希望将玩家集合传递到游戏视图模型。我该怎么做 从示意图上看,“我的视图”模型当前如下所示:C# 如何使用WinRT Caliburn.Micro将参数传递到导航视图模型?,c#,windows-runtime,windows-store-apps,caliburn.micro,C#,Windows Runtime,Windows Store Apps,Caliburn.micro,我正在使用WinRT Caliburn.Micro开发一个Windows应用商店应用程序游戏,我依赖于导航框架 我有游戏设置(定义玩家)和实际游戏的视图模型。当从设置导航到游戏时,我希望将玩家集合传递到游戏视图模型。我该怎么做 从示意图上看,“我的视图”模型当前如下所示: public class SetupGameViewModel : NavigationViewModelBase { public SetupGameViewModel(INavigationService ns)
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);
}
}
公共类SetupGameViewModel:NavigationViewModelBase
{
公共设置GameViewModel(INavigationService ns):基本(ns){}
公共IObservableCollection播放机{get;set;}
公共无效StartName()
{
//这是我所能做到的。。。
base.NavigationService.NavigateToViewModel();
//如何将玩家集合从此处传递到GameViewModel?
}
}
公共类GameViewModel:NavigationViewModelBase
{
公共游戏视图模型(INavigationService ns):基本(ns){}
公共记分板ViewModel记分板{get;private set;}
公共无效初始化Coreboard(IEnumerable玩家)
{
记分板=新记分板视图模型(球员);
}
}
理想情况下,我想从GameViewModel
构造函数中调用InitializeScoreBoard
,但据我所知,无法将SetupGameViewModel.Players
集合传递给GameViewModel
构造函数
INavigationService.NavigateToViewModel(扩展)方法可以选择使用
[object]参数
参数,但该参数似乎没有到达导航到的视图模型构造函数。我也不知道如何从SetupGameViewModel.StartGame
方法显式调用GameViewModel.InitializeScoreBoard
方法,因为GameViewModel
在此阶段尚未初始化。好的,将其放在那里,Caliburn.Micro
具有WP8和WinRT的统一导航:
NavigationService.UriFor<TargetViewModel>().WithParam(x => x.TargetProperty, ValueToPass).Navigate();
然后在详细信息视图模型中
:
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();
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<Player> Players {get;set;}
protected void OnInitialize()
{
//If everything goes as expected, Players should be populated now.
ScoreBoard = new ScoreBoard(Players);
}
}
公共类GameViewModel
{
公共游戏视图模型(INavigationService ns):基本(ns)
{
//在这里初始化播放器以避免null可能会很好
}
公共记分板ViewModel记分板{get;private set;}
公共IObservableCollection播放机{get;set;}
受保护的void OnInitialize()
{
//如果一切按预期进行,现在就应该填充玩家。
记分牌=新记分牌(球员);
}
}
但在实践中,我认为传递这样一个复杂的构造(类集合等)是行不通的
更多的基本类型可以正常工作(int
、string
、DateTime
等),但例如URI
对我不起作用,总是null
),所以最坏的情况/解决方法是,在导航之前将玩家
列表序列化为临时文件,并将文件路径作为字符串传递,以便在游戏视图模型
中反序列化
有更多的人参与到框架漫游中,因此,他们可能会为您提供更有价值的见解。最后,我通过实现一个临时事件处理程序解决了这个问题。事实证明,我可以使用
NavigateToViewModel(object)
重载来传递播放器集合
从中,我得到的印象是,这种方法只保证适用于“原始”类型,尽管在我的场景中,我至今没有发现任何问题
我的SetupGameViewModel.startName
方法现在实现如下:
public void StartGame()
{
base.NavigationService.Navigated += NavigationServiceOnNavigated;
base.NavigationService.NavigateToViewModel<GameViewModel>(Players);
base.NavigationService.Navigated -= 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应用程序中,您可以借助导航服务在视图模型之间切换复杂对象。仅在Silverlight应用程序中,您仅限于必须可序列化为字符串的对象。Win Store应用程序中不存在此限制 在您的情况下,类似于以下内容的内容应该会起作用。在startName()中,NavigationService用于调用GameViewModel。球员名单作为一个简单的参数移交。按照惯例,此参数将指定给目标ViewModel的特性参数
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
// ...
}
...
}
公共类设置GameViewModel:屏幕
{
私有只读INavigationService(导航服务);
公共主页视图模型(INavigationService导航服务)
{
_导航服务=导航服务;
}
公共IObservableCollection播放机{get;set;}
公共无效StartName()
{
_navigationService.NavigateToViewModel(玩家);
}
...
}
公共类GameViewModel:屏幕
{
私有IObservableCollection_参数;
公共IObservableCollection参数
{
获取{return\u参数;}
设置
{
if(value.Equals(_参数))返回;
_参数=值;
NotifyOfPropertyChange(()=>参数);
}
}
受保护的覆盖无效OnActivate()
{
//对玩家列表做些什么
// ...
}
...
}
更多关于这个主题的详细信息可以在这里找到:非常感谢,这是非常有用的信息,我从这个回复中学到了很多。但是,正如您所怀疑的那样,
Players
集合似乎无法通过WithParam
访问。我目前实现了一个非常笨拙的解决方案,为Navigated
事件定义了一个本地处理程序。事件参数给出了导航内容,我隐式地假设内容的DataContext
是我的视图模型。尽管如此,如果有人有一个更可靠的解决方案,这将是一件好事
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
// ...
}
...
}