Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
287 views
in Technique[技术] by (71.8m points)

c# - How to pass parameter to navigated view model with WinRT Caliburn.Micro?

I am developing a Windows Store apps game using WinRT Caliburn.Micro, and I am relying on the navigation framework.

I have view models for the game setup (define players) and the actual game. When navigating from the setup to the game, I want to pass the collection of players to the game view model. How can I do this?

Schematically, my view models currently look like this:

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);
    }
}

Ideally, I would like to call InitializeScoreBoard from within the GameViewModel constructor, but as far as I have been able to tell it is not possible to pass the SetupGameViewModel.Players collection to the GameViewModel constructor.

The INavigationService.NavigateToViewModel<T> (extension) method optionally takes an [object] parameter argument, but this parameter does not seem to reach the view model constructor navigated to. And I cannot figure out how to explicitly call the GameViewModel.InitializeScoreBoard method from the SetupGameViewModel.StartGame method either, since the GameViewModel has not been initialized at this stage.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

OK, just putting it out there, Caliburn.Micro has unified navigation for WP8 and WinRT:

NavigationService.UriFor<TargetViewModel>().WithParam(x => x.TargetProperty, ValueToPass).Navigate();

And you can chain WithParam for multiple parameters. Now there are some constraints, not all types go through, I'm not quite sure what the exact reason for that is, but it has something to do how the navigation works in WinRT. There was a mention of it somewhere in Caliburn.Micro discussion section.

Anyway, you can navigate this way. Don't rely on constructor though, It will call OnInitialize and OnActivate. So, just to cut it into the example:

NavigationService.UriFor<DetailsViewModel>().WithParam(x => x.Id, SelectedDetailsId).Navigate();

then in the DetailsViewModel:

protected override void OnInitialize()
{
    //Here you'll have Id property initialized to 'SelectedDetailsId' from the previous screen.
}

So, in pure theory, you could do:

NavigationService.UriFor<GameViewModel>().WithParam(x => x.Players, Players).Navigate();

in the setup and then:

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);
    }
}

In practice though, I don't think that passing a complex construct like that (collection of classes etc) is going to work.

More primitive types work just fine (int, string, DateTime etc., but e.g. URI didn't work for me, was always null), so worst-case scenario/workaround is, for example, to serialize the Players list to a temp file before the navigation and pass the file path as string to deserialize in the GameViewModel.

There are people more involved in the framework roaming the SO, they might give you more valuable insight.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...