【发布时间】:2011-02-21 23:55:54
【问题描述】:
我正在尝试使用 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 不应该知道它们关联的 View。
话不多说……有没有办法让我的 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
}
}
提前致谢, 杰里米
【问题讨论】:
-
您的 MainViewModel 是否有权访问您的播放器对象?如果是这样,难道 Player 对象上不能有一个名为 MoveUp() 的方法,那么在 KeyPressed 事件中你可以只调用 Player.MoveUp() 吗?这样一来,Player 的移动逻辑仍然在 Player 对象中。
-
不,它没有对 Player 对象的引用。它没有任何对 XAML 的引用,这就是我认为 MVVM 应该如何工作的方式。有没有办法可以将 Player 的 XAML 实例绑定到 MainViewModel 中的变量?
标签: .net silverlight mvvm silverlight-4.0 mvvm-light