Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用WinRT Caliburn.Micro将参数传递到导航视图模型?_C#_Windows Runtime_Windows Store Apps_Caliburn.micro - Fatal编程技术网

C# 如何使用WinRT Caliburn.Micro将参数传递到导航视图模型?

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)

我正在使用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);
    }
}
公共类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
        // ...
    }

    ...
}