代码之家  ›  专栏  ›  技术社区  ›  jturinetti

Silverlight 4+MVVM+KeyDown事件

  •  5
  • jturinetti  · 技术社区  · 16 年前

    我正在尝试使用MVVM设计模式在Silverlight4中构建一个示例游戏,以拓宽我的知识面。我也在使用Laurent Bugnion的MVVMlight工具包(在这里找到: http://mvvmlight.codeplex.com/ )我现在要做的就是通过按特定键在画布内移动形状。我的解决方案包含player.xaml(只是一个矩形;它将被移动)和mainpage.xaml(画布和player控件的一个实例)。

    据我所知,Silverlight不支持隧道路由事件,只支持冒泡。我的大问题是player.xaml无法识别keydown事件。它总是先被mainpage.xaml截获,并且它永远不会到达任何子控件,因为它向上冒泡。我希望移动播放器的逻辑在playerview模型类中,但是我认为如果没有我从主页上明确地传递它们,播放器就不能知道任何键控事件触发。

    我最终将处理程序逻辑添加到了mainpageviewModel类中。现在我的问题是mainpageviewModel不知道player.xaml,因此它在处理keydown事件时无法移动此对象。我想这是意料之中的,因为视图模型不应该知道它们关联的视图。

    用不了那么多的话……在我的mainpage.xaml中,这个播放器用户控件是否可以直接接受和处理keydown事件?如果不是,我的MainpageViewModel与其视图的子控件通信的理想方法是什么?我正在尽可能地让代码远离文件背后的代码。似乎最好将逻辑放在视图模型中以便于测试,并将UI与逻辑分离。

    (主页,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>
    

    (主视图模型.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
            }
    }
    

    事先谢谢, 杰瑞米

    1 回复  |  直到 16 年前
        1
  •  3
  •   LBugnion    16 年前

    不要使用EventTrigger,请尝试使用KeyTrigger并将源对象设置为LayoutRoot。

    另一个选择(我认为更好)是让ViewModel处理播放器的位置。例如,有一个名为playertop的属性和一个名为playerLeft的属性。将播放器的canvas.top和canvas.left属性绑定到这些。当用户按下键时,会在虚拟机上执行一个命令来更新这些属性。这样,虚拟机就不必知道移动了什么,或者如何移动。

    这有道理吗?