Próbuję zbudować przykładową grę w Silverlight 4 przy użyciu wzorca projektowego MVVM, aby poszerzyć moją wiedzę. Używam również zestawu narzędzi MvvmLight Laurenta Bugniona (tutaj: http://mvvmlight.codeplex.com/). Wszystko, co chcę teraz zrobić, to przesuwać kształt wokół płótna, naciskając określone klawisze. Moje rozwiązanie zawiera Player.xaml (tylko prostokąt, to zostanie przeniesione) i MainPage.xaml (Canvas i instancja kontrolki Player).Silverlight 4 + MVVM + wydarzenie KeyDown
Silverlight nie obsługuje tunelowania zdarzeń routowanych, a jedynie propagacji. Mój wielki problem polega na tym, że Player.xaml nigdy nie rozpoznaje zdarzenia KeyDown. Zawsze jest on przechwytywany najpierw przez MainPage.xaml i nigdy nie osiąga żadnych kontrolek podrzędnych, ponieważ pęcznieje w górę. Wolałbym, żeby logika przeniesienia Gracza była w klasie PlayerViewModel, ale nie sądzę, aby Gracz wiedział o jakichkolwiek zdarzeniach KeyDown strzelających bez mnie, jawnie przekazujących je z MainPage.
Skończyło się na dodaniu logiki obsługi do klasy MainPageViewModel. Teraz mój problem polega na tym, że MainPageViewModel nie ma wiedzy o Player.xaml, więc nie może przenieść tego obiektu podczas obsługi zdarzeń KeyDown. Sądzę, że jest to oczekiwane, ponieważ ViewModels nie powinien mieć żadnej wiedzy na temat powiązanych widoków.
W nie tak wielu słowach ... czy istnieje sposób, w jaki kontrolka użytkownika tego odtwarzacza na mojej stronie głównej może bezpośrednio akceptować zdarzenia KeyDown? Jeśli nie, jaka jest idealna metoda, aby mój MainPageViewModel mógł komunikować się z kontrolkami podrzędnymi tego widoku? Próbuję zachować kod z plików za kodem tak bardzo, jak to tylko możliwe. Wydaje się, że najlepiej jest umieścić logikę w ViewModels dla łatwości testowania i odłączyć interfejs użytkownika od logiki.
(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
}
}
Dzięki z góry Jeremy
Czy Twój MainViewModel ma dostęp do twojego obiektu gracza? Jeśli tak, to czy obiekt Player nie mógł mieć metody o nazwie MoveUp(), a następnie w zdarzeniu KeyPressed można po prostu wywołać Player.MoveUp()? W ten sposób logika przemieszczania się odtwarzacza będzie nadal w obiekcie odtwarzacza. – JSprang
Nie, nie ma odniesienia do obiektu odtwarzacza. Nie ma żadnego odniesienia do XAML, tak jak myślałem, że MVVM ma działać. Czy istnieje sposób, w jaki mogę powiązać moją instancję XAML odtwarzacza z zmienną w MainViewModel? – jturinetti