我正在尝试使用 MVVM 设计模式在 Silverlight 4 中构建示例游戏以拓宽我的知识。我也在使用 Laurent Bugnion 的 MvvmLight 工具包(可在此处找到:http://mvvmlight.codeplex.com/ )。我现在要做的就是通过按特定键在画布内移动一个形状。我的解决方案包含一个 Player.xaml(只是一个矩形;它将四处移动)和 MainPage.xaml(Canvas 和 Player 控件的一个实例)。
据我了解,Silverlight 不支持隧道路由事件,仅支持冒泡。我的大问题是 Player.xaml 永远无法识别 KeyDown 事件。它总是首先被 MainPage.xaml 拦截,并且它永远不会到达任何子控件,因为它会向上冒泡。我更希望将 Player 移动的逻辑位于 PlayerViewModel 类中,但我认为如果没有我从 MainPage 显式传递它们,Player 无法知道任何触发的 KeyDown 事件。
我最终将处理程序逻辑添加到 MainPageViewModel 类。现在我的问题是 MainPageViewModel 不了解 Player.xaml,因此在处理 KeyDown 事件时它无法移动此对象。我想这是意料之中的,因为 ViewModel 不应该知道它们的关联视图。
不多说……有没有办法让我的 MainPage.xaml 中的 Player 用户控件直接接受和处理 KeyDown 事件?如果不是,我的 MainPageViewModel 与其 View 的子控件进行通信的理想方法是什么?我试图将代码尽可能地保留在代码隐藏文件之外。似乎最好将逻辑放在 ViewModel 中以便于测试并将 UI 与逻辑分离。
(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
}
}
在此先感谢,杰里米