2010-05-20 3 views
5

Sto provando a creare un gioco di esempio in Silverlight 4 utilizzando il modello di progettazione MVVM per ampliare le mie conoscenze. Uso anche il toolkit MvvmLight di Laurent Bugnion (disponibile qui: http://mvvmlight.codeplex.com/). Tutto quello che voglio fare adesso è spostare una forma all'interno di una tela premendo tasti specifici. La mia soluzione contiene un Player.xaml (solo un rettangolo che verrà spostato) e MainPage.xaml (il Canvas e un'istanza del controllo Player).Silverlight 4 + MVVM + KeyDown evento

Per la mia comprensione, Silverlight non supporta tunneling eventi indirizzati, solo spumeggiante. Il mio grosso problema è che Player.xaml non riconosce mai l'evento KeyDown. Viene sempre prima intercettato da MainPage.xaml e non raggiunge mai alcun controllo figlio perché bolle verso l'alto. Preferirei che la logica per spostare il Player sia nella classe PlayerViewModel, ma non penso che il Player possa sapere di eventuali eventi KeyDown che si attivano senza che io li faccia esplicitamente passare da MainPage.

ho finito di aggiungere la logica gestore alla classe MainPageViewModel. Ora il mio problema è che il MainPageViewModel non ha alcuna conoscenza di Player.xaml, quindi non può spostare questo oggetto quando gestisce eventi KeyDown. Immagino che questo è previsto, in quanto ViewModels non dovrebbe avere alcuna conoscenza delle loro viste associate.

In non così tante parole ... c'è un modo in cui questo controllo utente Player nel mio MainPage.xaml può accettare e gestire gli eventi KeyDown direttamente? In caso contrario, qual è il metodo ideale per il mio MainPageViewModel per comunicare con i controlli figlio di View? Sto cercando di mantenere il codice dei file code-behind il più possibile. Sembra che sia meglio mettere la logica in ViewModels per facilità di test e per disaccoppiare l'interfaccia utente dalla logica.

(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 
     } 
} 

Grazie in anticipo, Jeremy

+0

Il tuo MainViewModel ha accesso al tuo oggetto giocatore? In tal caso, non è possibile che l'oggetto Player abbia un metodo chiamato MoveUp(), quindi nell'evento KeyPressed è possibile chiamare Player.MoveUp()? In questo modo, la logica per lo spostamento del Player sarebbe ancora nell'oggetto Player. – JSprang

+0

No, non ha un riferimento all'oggetto Player. Non ha alcun riferimento allo XAML, ed è così che pensavo che MVVM avrebbe dovuto funzionare. C'è un modo per legare la mia istanza XAML del Player a una variabile in MainViewModel? – jturinetti

risposta

3

Invece di usare l'EventTrigger, cercare di usa KeyTrigger e imposta l'oggetto Source come LayoutRoot.

Un'altra opzione (che credo sia meglio) è di lasciare che il ViewModel gestire la posizione del giocatore. Ad esempio, avere una proprietà denominata PlayerTop e una proprietà denominata PlayerLeft. Associa la proprietà Canvas.Top e Canvas.Left di PLayer a questi. Quando l'utente preme i tasti, viene eseguito un comando sulla VM che aggiorna queste proprietà. In questo modo la VM non deve sapere cosa viene spostato o come viene spostato.

Ha senso?

+0

Grazie! Ho finito per usare il tuo ultimo suggerimento. Avevo ancora un problema ... perché il Player aveva il suo DataContext associato al suo PlayerViewModel nel suo XAML a livello UserControl, i collegamenti Canvas.Top e Canvas.Left di Player in MainPage.xaml non potevano trovare le proprietà PlayerTop/PlayerLeft . Ho dovuto spostare il binding DataContext del player fino al controllo di root della griglia. – jturinetti