2010-05-20 109 views
5

我想在Silverlight 4中使用MVVM設計模式來擴展我的知識來構建一個示例遊戲。我也使用Laurent Bugnion的MvvmLight工具包(在這裏找到:http://mvvmlight.codeplex.com/)。我現在想要做的就是通過按特定鍵在Canvas中移動一個形狀。我的解決方案包含一個Player.xaml(只是一個矩形;這將被移動)和MainPage.xaml(Canvas和Player控件的一個實例)。Silverlight 4 + MVVM + KeyDown事件

據我的理解,Silverlight不支持隧道路由事件,只冒泡。我的大問題是Player.xaml永遠不會識別KeyDown事件。它總是首先被MainPage.xaml攔截,它永遠不會到達任何子控件,因爲它向上冒泡。我更喜歡移動播放器的邏輯是在PlayerViewModel類中,但我不認爲播放器可以知道任何KeyDown事件沒有我明確地從MainPage傳遞它們。

我最終將處理程序邏輯添加到MainPageViewModel類。現在我的問題是,MainPageViewModel不知道Player.xaml,所以在處理KeyDown事件時它不能移動這個對象。我想這是預期的,因爲ViewModels不應該有任何關於它們相關視圖的知識。

沒有那麼多的話......這個Player用戶在我的MainPage.xaml中控制的方式是否可以直接接受和處理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 
     } 
} 

由於提前, 傑里米

+0

您的MainViewModel是否可以訪問您的播放器對象?如果是這樣,那麼Player對象上就不能有一個名爲MoveUp()的方法,那麼在KeyPressed事件中,你可以調用Player.MoveUp()?這樣,播放器移動的邏輯仍然在Player對象中。 – JSprang 2010-05-20 17:23:04

+0

不,它沒有對Player對象的引用。它沒有提及任何XAML,這是我認爲MVVM應該如何工作的。有沒有一種方法可以將我的Pl​​ayer的XAML實例綁定到MainViewModel中的變量? – jturinetti 2010-05-21 15:29:34

回答

3

除了使用EventTrigger,儘量使用KeyTrigger並將Source對象設置爲LayoutRoot。

另一種選擇(我認爲更好)是讓ViewModel處理玩家的位置。例如,有一個名爲PlayerTop的屬性和一個名爲PlayerLeft的屬性。將PLayer的Canvas.Top和Canvas.Left屬性綁定到這些屬性上。當用戶按下按鍵時,會在更新這些屬性的VM上執行命令。這樣虛擬機就不必知道什麼是移動的,或者它是如何移動的。

這有道理嗎?

+0

謝謝!我結束了使用你的後一個建議。我還有一個問題,因爲Player在其UserContext級別的XAML中將其DataContext綁定到它的PlayerViewModel,MainPage.xaml中的Player的Canvas.Top和Canvas.Left綁定找不到PlayerTop/PlayerLeft屬性。我必須將播放器的DataContext綁定向下移動到其網格根控件。 – jturinetti 2010-05-21 18:51:43