Wpf 在MVVM中使用命令

Wpf 在MVVM中使用命令,wpf,mvvm,mvvm-light,Wpf,Mvvm,Mvvm Light,我一直在使用来自的非常好的示例代码来了解如何有效地使用 在代码中,在一个实例中,作者似乎只是利用代码来设置DataContext以处理单击事件,这让我感到困惑 在XAML中,上下文菜单cm中菜单项的EditNote\u单击事件处理程序在代码隐藏中处理: <Window x:Class="ApuntaNotas.MainWindow" Icon="Icons/app_48.ico" xmlns="http://schemas.microsoft.com/win

我一直在使用来自的非常好的示例代码来了解如何有效地使用

在代码中,在一个实例中,作者似乎只是利用代码来设置DataContext以处理单击事件,这让我感到困惑

在XAML中,上下文菜单
cm
中菜单项的
EditNote\u单击事件处理程序在代码隐藏中处理:

    <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>
.
.
.
EditNoteCommand
具有以下签名:

public RelayCommand<Note> EditNoteCommand { get; private set; }
此尝试针对
EditNote
中的
other
生成以下异常,该方法由
EditNoteCommand
调用:

编辑注:

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:

除非有必要,否则您肯定是在正确的轨道上不想使用代码隐藏,所以在MVVM中继续遵循这一原则,您会做得很好

我想你会发现作者在这里使用代码来解决一个问题,使命令参数正确。 对于“编辑注释”命令,所编辑注释的视图模型是必需的参数。这就是他们在代码背后所做的-

menuItem.DataContext as Model.Note
您遇到的问题是如何在同一命令中访问已单击的菜单项和“主”视图模型

如果要将
EditNoteCommand
移动到NotesViewModel(或任何Notes类)中,则可以将命令保存在XAML中,如下所示:

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

嗯,,
Scott

我们可能不需要完整的堆栈跟踪:我看完整堆栈跟踪没有问题。@Phil-你应该编辑答案来修正拼写。然后,具有适当代表级别的人会来批准您的更改。记住,你现在可以做到了。谢谢斯科特。模型。注释是注释的模型,而不是viewmodel。注意:实际上没有viewmodel。Model.Note是一个模型而不是viewmodel这一事实会改变您的分析吗?FWIW,Notes只是一个可观察的集合。@Bill-欢迎Bill-我认为Notes将是现在拥有虚拟机的首选,即使它以前只是一个模型。特别是它现在将有命令,毫无疑问INotifyPropertyChanged实现即将到来(用于在编辑结束后更新UI)。再次感谢Scott。您对模型对象或其他对象何时可能“升级”到保证ViewModel的额外见解对我非常有帮助。如果您能想到任何其他经验法则指导原则或参考,用于将UI元素映射到ViewModels,那么它将非常受欢迎。
menuItem.DataContext as Model.Note
<MenuItem Header="{Binding Source={StaticResource LocStrings}, Path=Edit}" Command="{Binding EditNoteCommand}" />