5

知識を広げるために、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 から明示的に渡さなければ KeyDown イベントの発生を Player が認識できないと思います。

最終的に、ハンドラー ロジックを MainPageViewModel クラスに追加しました。今私の問題は、MainPageViewModel が Player.xaml を認識していないため、KeyDown イベントを処理するときにこのオブジェクトを移動できないことです。ViewModels は関連付けられた Views の知識を持っていないはずなので、これは予想されることだと思います。

それほど多くの言葉ではありません... MainPage.xaml 内のこの Player ユーザー コントロールが KeyDown イベントを直接受け入れて処理できる方法はありますか? そうでない場合、MainPageViewModel がビューの子コントロールと通信するための理想的な方法は何ですか? 分離コード ファイルにコードをできるだけ入れないようにしています。テストを容易にし、UI をロジックから切り離すために、ViewModel にロジックを配置するのが最善のようです。

(メインページ.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
        }
}

前もって感謝します、ジェレミー

4

1 に答える 1

3

EventTrigger を使用する代わりに、KeyTrigger を使用して、Source オブジェクトを LayoutRoot に設定してみてください。

もう 1 つのオプション (こちらの方が良いと思います) は、ViewModel にプレーヤーの位置を処理させることです。たとえば、PlayerTop という名前のプロパティと PlayerLeft という名前のプロパティがあります。PLayer の Canvas.Top および Canvas.Left プロパティをこれらにバインドします。ユーザーがキーを押すと、これらのプロパティを更新するコマンドが VM で実行されます。この方法では、VM は移動対象や移動方法を認識する必要がありません。

それは理にかなっていますか?

于 2010-05-21T15:42:28.297 に答える