Comment passer un paramètre au modèle de vue parcouru avec WinRT Caliburn.Micro?

Je développe un jeu d’applications Windows Store à l’aide de WinRT Caliburn.Micro et je me base sur le cadre de navigation.

J’ai des modèles de vue pour la configuration du jeu (définir les joueurs) et le jeu réel. Lors de la navigation de la configuration au jeu, je souhaite transmettre la collection de joueurs au modèle de vue du jeu. Comment puis-je faire ceci?

Schématiquement, mes modèles de vue se présentent comme suit:

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

Idéalement, j’aimerais appeler InitializeScoreBoard partir du constructeur GameViewModel , mais pour autant que je GameViewModel , il n’est pas possible de transmettre la collection GameViewModel constructeur GameViewModel .

La INavigationService.NavigateToViewModel (extension) prend éventuellement un argument de [object] parameter , mais ce paramètre ne semble pas atteindre le constructeur du modèle de vue INavigationService.NavigateToViewModel . Et je ne peux pas comprendre comment appeler explicitement la méthode GameViewModel.InitializeScoreBoard partir de la méthode SetupGameViewModel.StartGame , car GameViewModel n’a pas été initialisé à ce stade.

OK, Caliburn.Micro a unifié la navigation pour WP8 et WinRT:

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

Et vous pouvez chaîner WithParam pour plusieurs parameters. Maintenant, il y a des contraintes, tous les types ne sont pas acceptés, je ne suis pas sûr de la raison exacte, mais cela a quelque chose à voir avec le fonctionnement de la navigation dans WinRT. On en a parlé quelque part dans la section de discussion de Caliburn.Micro .

Quoi qu’il en soit, vous pouvez naviguer de cette façon. Ne comptez pas sur le constructeur, il appellera OnInitialize et OnActivate . Donc, juste pour le couper dans l’exemple:

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

puis dans le DetailsViewModel :

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

Donc, en théorie pure, vous pourriez faire:

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

dans la configuration et ensuite:

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

En pratique cependant, je ne pense pas que passer une construction complexe comme celle-ci (collection de classes, etc.) va marcher.

Les types plus primitifs fonctionnent très bien ( int , ssortingng , DateTime etc., mais l’ URI ne fonctionnait pas pour moi, était toujours null ), le pire cas de contournement consiste donc, par exemple, à sérialiser la liste des Players sur une liste fichier avant la navigation et transmettez le chemin du fichier sous forme de chaîne à désérialiser dans GameViewModel .

Il y a des personnes plus impliquées dans le cadre d’itinérance du SO, elles pourraient vous donner des informations plus utiles.

En fin de compte, j’ai résolu ce problème en mettant en œuvre un gestionnaire d’événements temporaire. Il s’est avéré que je pouvais utiliser la surcharge NavigateToViewModel(object) pour transmettre la collection de lecteurs.

D’après le forum de discussion Caliburn Micro et la documentation MSDN, j’ai l’impression que cette approche ne fonctionnera que pour les types “primitifs”, bien que, dans mon scénario, je n’ai jusqu’à présent détecté aucun problème.

Ma méthode SetupGameViewModel.StartGame est maintenant implémentée comme suit:

 public void StartGame() { base.NavigationService.Navigated += NavigationServiceOnNavigated; base.NavigationService.NavigateToViewModel(Players); base.NavigationService.Navigated -= NavigationServiceOnNavigated; } 

Et le gestionnaire d’événements NavigationServiceOnNavigated très temporairement attaché est implémenté comme suit:

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

Pas vraiment la solution propre que je cherchais, mais au moins elle semble fonctionner.

Dans Win Store Apps, vous pouvez transférer des objects complexes entre ViewModels à l’aide de NavigationService. Dans Silverlight Apps uniquement, vous ne pouvez utiliser que des objects pouvant être sérialisés en une chaîne. Cette ressortingction n’existe pas dans les applications Win Store.

Dans votre cas, quelque chose comme ce qui suit devrait fonctionner. Dans StartGame (), NavigationService est utilisé pour appeler GameViewModel. La liste des joueurs est transmise sous forme de paramètre simple. Par convention, ce paramètre sera affecté à une propriété Paramètre du ViewModel de destination.

 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 // ... } ... } 

Des informations plus détaillées sur ce sujet sont disponibles à l’ adresse suivante : http://wp.qmatteoq.com/using-caliburn-micro-with-universal-windows-app-navigation/