2010-05-20 6 views
5

J'essaie de créer un exemple de jeu dans Silverlight 4 en utilisant le modèle de conception MVVM pour élargir mes connaissances. J'utilise également la boîte à outils MvvmLight de Laurent Bugnion (disponible ici: http://mvvmlight.codeplex.com/). Tout ce que je veux faire maintenant est de déplacer une forme autour d'un canevas en appuyant sur des touches spécifiques. Ma solution contient un Player.xaml (juste un rectangle, qui sera déplacé) et MainPage.xaml (le Canvas et une instance du contrôle Player). À ma connaissance, Silverlight ne prend pas en charge les événements routés de tunnellisation, mais uniquement le bouillonnement. Mon gros problème est que Player.xaml ne reconnaît jamais l'événement KeyDown. Il est toujours intercepté par MainPage.xaml en premier et il n'atteint jamais les contrôles enfants car il fait des bulles vers le haut. Je préférerais que la logique pour déplacer le joueur soit dans la classe PlayerViewModel, mais je ne pense pas que le joueur puisse savoir que des événements KeyDown se déclenchent sans que je ne les transmette explicitement à partir de MainPage.Événement Silverlight 4 + MVVM + KeyDown

J'ai fini par ajouter la logique du gestionnaire à la classe MainPageViewModel. Maintenant, mon problème est que le MainPageViewModel n'a aucune connaissance de Player.xaml donc il ne peut pas déplacer cet objet lors de la gestion des événements KeyDown. Je suppose que cela est prévu, car ViewModels ne devrait avoir aucune connaissance de leurs vues associées.

Dans pas tellement de mots ... est-il un moyen que ce contrôle utilisateur Player dans mon MainPage.xaml peut directement accepter et gérer les événements KeyDown? Si non, quelle est la méthode idéale pour que mon MainPageViewModel communique avec les contrôles enfants de View? J'essaie de garder le code des fichiers code-behind autant que possible. On dirait qu'il est préférable de mettre de la logique dans les ViewModels pour faciliter les tests et découpler l'interface utilisateur de la logique.

(MainPage.xaml)

<UserControl x:Class="MvvmSampleGame.MainPage" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:game="clr-namespace:MvvmSampleGame"    
     xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
     xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.SL4" 
     mc:Ignorable="d" 
     Height="300" 
     Width="300" 
     DataContext="{Binding Main, Source={StaticResource Locator}}"> 

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="KeyDown"> 
     <cmd:EventToCommand Command="{Binding KeyPressCommand}" PassEventArgsToCommand="True" /> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

<Canvas x:Name="LayoutRoot">  
    <game:Player x:Name="Player1"></game:Player> 
</Canvas> 

(MainViewModel.cs)

public MainViewModel() 
{ 

    KeyPressCommand = new RelayCommand<KeyEventArgs>(KeyPressed); 

}  

public RelayCommand<KeyEventArgs> KeyPressCommand 
{ 
    get; 
    private set; 
} 

private void KeyPressed(KeyEventArgs e) 
{ 

     if (e.Key == Key.Up || e.Key == Key.W) 
     { 
      // move player up 

     } 
     else if (e.Key == Key.Left || e.Key == Key.A) 
     { 
      // move player left 
     } 
     else if (e.Key == Key.Down || e.Key == Key.S) 
     { 
      // move player down 
     } 
     else if (e.Key == Key.Right || e.Key == Key.D) 
     { 
      // move player right 
     } 
} 

Merci à l'avance, Jeremy

+0

Est-ce que votre MainViewModel a accès à votre objet joueur? Si oui, l'objet Player ne peut-il pas avoir une méthode appelée MoveUp(), alors dans l'événement KeyPressed, vous pouvez simplement appeler Player.MoveUp()? De cette façon, la logique du déplacement du joueur serait toujours dans l'objet Player. – JSprang

+0

Non, il ne contient aucune référence à l'objet Player. Il n'a aucune référence au XAML, ce que je pensais que MVVM était censé fonctionner. Est-il possible de lier mon instance XAML du lecteur à une variable dans MainViewModel? – jturinetti

Répondre

3

Au lieu d'utiliser le EventTrigger, essayez de utilisez KeyTrigger et définissez l'objet Source sur LayoutRoot.

Une autre option (que je pense préférable) est de laisser le ViewModel gérer la position du lecteur. Par exemple, possédez une propriété appelée PlayerTop et une propriété nommée PlayerLeft. Liez la propriété Canvas.Top et Canvas.Left du Layer à celles-ci. Lorsque l'utilisateur appuie sur les touches, une commande est exécutée sur la machine virtuelle qui met à jour ces propriétés. De cette façon, la VM n'a pas besoin de savoir ce qui est déplacé ou comment il est déplacé.

Est-ce que cela a du sens?

+0

Merci! J'ai fini par utiliser votre dernière suggestion. J'ai eu un autre problème cependant ... parce que le lecteur avait son DataContext lié à son PlayerViewModel dans son XAML au niveau UserControl, les liaisons Canvas.Top et Canvas.Left du Player dans MainPage.xaml n'ont pas pu trouver les propriétés PlayerTop/PlayerLeft . Je devais déplacer la liaison DataContext du lecteur vers son contrôle racine. – jturinetti