Estoy intentando crear un juego de muestra en Silverlight 4 usando el patrón de diseño de MVVM para ampliar mi conocimiento. Estoy usando el kit de herramientas MvvmLight de Laurent Bugnion también (se encuentra aquí: http://mvvmlight.codeplex.com/). Todo lo que quiero hacer ahora es mover una forma dentro de un lienzo presionando teclas específicas. Mi solución contiene un Player.xaml (solo un rectángulo, este se moverá) y MainPage.xaml (el lienzo y una instancia del control del reproductor).Evento Silverlight 4 + MVVM + KeyDown
A mi entender, Silverlight no admite eventos enrutados de túnel, solo burbujeo. Mi gran problema es que Player.xaml nunca reconoce el evento KeyDown. Siempre es interceptado por MainPage.xaml primero y nunca llega a los controles secundarios porque se dispara hacia arriba. Preferiría que la lógica para mover el Reproductor esté en la clase PlayerViewModel, pero no creo que el Jugador pueda saber sobre ningún evento KeyDown que se active sin que yo los pase explícitamente desde MainPage.
Terminé agregando la lógica del controlador a la clase MainPageViewModel. Ahora mi problema es que MainPageViewModel no tiene conocimiento de Player.xaml por lo que no puede mover este objeto cuando maneja eventos KeyDown. Supongo que esto se espera, ya que ViewModels no debería tener ningún conocimiento de sus Vistas asociadas.
En pocas palabras ... ¿hay alguna forma de que este control de usuario Player en mi MainPage.xaml acepte y maneje directamente eventos KeyDown? Si no, ¿cuál es el método ideal para que mi MainPageViewModel se comunique con los controles secundarios de su Vista? Estoy tratando de mantener el código fuera de los archivos de código subyacente tanto como sea posible. Parece que es mejor poner lógica en ViewModels para facilitar la prueba y desacoplar UI de la lógica.
(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
}
}
Gracias de antemano, Jeremy
¿Su MainViewModel tiene acceso a su objeto de jugador? Si es así, ¿no podría el objeto Player tener un método llamado MoveUp(), entonces en el evento KeyPressed podría simplemente llamar a Player.MoveUp()? De esta manera, la lógica para el movimiento del jugador aún estaría en el objeto Player. – JSprang
No, no tiene una referencia al objeto Player. No tiene ninguna referencia al XAML en absoluto, que es como pensé que se suponía que MVVM funcionara. ¿Hay alguna manera de vincular mi instancia XAML del reproductor a una variable en MainViewModel? – jturinetti