2011-02-23 91 views
1

我一直在使用來自ApuntasNotas的非常好的示例代碼來了解更多有關如何有效使用MVVM Light Toolkit的信息。在MVVM中使用命令

在代碼中,在一個實例中,作者似乎利用背後的代碼來設置DataContext來處理單擊事件,這讓我感到困惑。

在XAML,在文本菜單cm一個菜單項的EditNote_Click事件處理程序中的代碼隱藏的處理:

<Window x:Class="ApuntaNotas.MainWindow" Icon="Icons/app_48.ico" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      Title="Apunta Notas" 
      Height="480" 
      x:Name="Ventana" 
      Width="640" 
      Background="Beige" 
      DataContext="{Binding Main, Source={StaticResource Locator}}"> 
. 
. 
. 
<ScrollViewer VerticalScrollBarVisibility="Auto"> 
      <ItemsControl Background="Beige" Padding="15" Tag="Hello" x:Name="IC" 
         ItemsSource="{Binding Notes}"> 
       <ItemsControl.LayoutTransform> 
        <ScaleTransform ScaleX="{Binding Value, ElementName=zoomSlider}" ScaleY="{Binding Value, ElementName=zoomSlider}" /> 
       </ItemsControl.LayoutTransform> 
       <ItemsControl.ContextMenu> 
        <ContextMenu Name="icCM"> 
         <MenuItem Header="{Binding Source={StaticResource LocStrings}, Path=DeleteAllNotes}" Command="{Binding DeleteAllNotesCommand}" /> 
        </ContextMenu> 
       </ItemsControl.ContextMenu> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <Grid> 
          <Grid.ColumnDefinitions> 
           <ColumnDefinition Width="auto" /> 
           <ColumnDefinition Width="*" /> 
          </Grid.ColumnDefinitions> 
          <Grid.ContextMenu> 
           <ContextMenu Name="cm"> 
            <MenuItem Header="{Binding Source={StaticResource LocStrings}, Path=Edit}" Click="EditNote_Click"/> 
            <MenuItem Header="{Binding Source={StaticResource LocStrings}, Path=Delete}" Click="DeleteNote_Click" /> 
            <Separator /> 
            <ComboBox Loaded="CmbNoteCategory_Loaded" SelectionChanged="CmbNoteCategory_SelectionChanged"> 
             <ComboBox.ItemTemplate> 
              <DataTemplate> 
               <TextBlock Text="{Binding Name}" /> 
              </DataTemplate> 
             </ComboBox.ItemTemplate> 
            </ComboBox> 
           </ContextMenu> 
. 
. 
. 

在代碼隱藏中,EditNote_Click處理程序的定義如下:

private void EditNote_Click(object sender, RoutedEventArgs e) 
     { 
      var menuItem = e.Source as MenuItem; 
      if (menuItem != null) 
       ViewModel.EditNoteCommand.Execute(menuItem.DataContext as Model.Note); 
     } 

EditNoteCommand具有以下特徵:

public RelayCommand<Note> EditNoteCommand { get; private set; } 

我的問題是,爲什麼作者沒有將EditNoteCommand命令(已寫入且可用)與MenuItemCommand屬性鏈接到XAML中?

例如,我試圖替換下列內容,它編譯了,但生成了一個異常(如下所示)。我懷疑我的方法是合理的,但我錯過了將DataContext或其他內容傳遞給命令代碼的內容。我重置的DataContext綁定到Main便於命令結合:

<MenuItem Header="{Binding Source={StaticResource LocStrings}, Path=Edit}" DataContext="{Binding Main, Source={StaticResource Locator}}" Command="{Binding EditNoteCommand}"/> 

這種嘗試產生內EditNote參照other以下異常 - 一個通過EditNoteCommand調用的方法:

EditNote:

private void EditNote(Note other) 
     { 
      ActualNote = other; 
      SelectedCategory = other.Category; 
     } 

例外:

System.NullReferenceException was unhandled Message=Object reference not set to an instance of an object. Source=ApuntaNotas StackTrace: 
     at ApuntaNotas.ViewModel.MainViewModel.EditNote(Note other) in C:\Documents and Settings\wcatlan\My Documents\Visual Studio 2010\Projects\ApuntaNotas\trunk\ApuntaNotas\ViewModel\MainViewModel.cs:line 171 
     at GalaSoft.MvvmLight.Command.RelayCommand`1.Execute(Object parameter) 
     at MS.Internal.Commands.CommandHelpers.CriticalExecuteCommandSource(ICommandSource commandSource, Boolean userInitiated) 
     at System.Windows.Controls.MenuItem.InvokeClickAfterRender(Object arg) 
     at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) 
     at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler) 
     at System.Windows.Threading.DispatcherOperation.InvokeImpl() 
     at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state) 
     at System.Threading.ExecutionContext.runTryCode(Object userData) 
     at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) 
     at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
     at System.Windows.Threading.DispatcherOperation.Invoke() 
     at System.Windows.Threading.Dispatcher.ProcessQueue() 
     at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) 
     at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) 
     at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) 
     at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) 
     at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler) 
     at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) 
     at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) 
     at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) 
     at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) 
     at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame) 
     at System.Windows.Threading.Dispatcher.Run() 
     at System.Windows.Application.RunDispatcher(Object ignore) 
     at System.Windows.Application.RunInternal(Window window) 
     at System.Windows.Application.Run(Window window) 
     at System.Windows.Application.Run() 
     at ApuntaNotas.App.Main() in C:\Documents and Settings\wcatlan\My Documents\Visual Studio 2010\Projects\ApuntaNotas\trunk\ApuntaNotas\obj\Debug\App.g.cs:line 0 
     at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
     at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
     at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
     at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
     at System.Threading.ThreadHelper.ThreadStart() InnerException: 
+0

我們可能沒」 t需要完整的堆棧跟蹤。 :) – 2011-02-23 13:01:03

+0

我看到完整的堆棧跟蹤沒有問題。 – Robaticus 2011-02-23 13:25:16

回答

3

你絕對是在正確的軌道上,因爲除非需要,否則不想使用代碼隱藏 - 所以請在MVVM中遵循該委託人,並且你會做得很好。

我想你會發現作者在這裏使用代碼隱藏來解決獲取命令參數正確的問題。 對於編輯註釋命令 - 正在編輯的音符的視圖模型是必需的參數。這是他們在代碼正在做的事情背後這裏 -

menuItem.DataContext as Model.Note 

您遇到的問題是有關獲取訪問被點擊,並在同一個命令「主」視圖模型的菜單項。

如果你到EditNoteCommand移動到NotesViewModel(或任何課堂筆記是),你可以在XAML保持你的命令是這樣的:

<MenuItem Header="{Binding Source={StaticResource LocStrings}, Path=Edit}" Command="{Binding EditNoteCommand}" /> 

HTH, 斯科特

+0

讀「你的」,而不是「你」,給我一個腦部痙攣。 – 2011-02-23 12:57:13

+0

@菲爾 - 你應該編輯答案來解決拼寫問題。然後有適當級別代表的人會來,並批准您的更改。請記住,現在你可以做到這一點。 – Robaticus 2011-02-23 13:24:36

+0

謝謝斯科特。 Model.Note是Note的模型,而不是視圖模型。注意實際上沒有視圖模型。 Model.Note是一個模型,而不是視圖模型會改變你的分析嗎? FWIW,Notes只是一個ObservableCollection 。 – Bill 2011-02-23 13:59:48