我正在开发我的第一个WPF应用程序,并试图坚持使用MVVM方法。我正在使用MVVM Light。它是一个简单的应用程序,它仅显示一个称为“合并”的列表,并允许用户选择一个列表并进行编辑。
我有MainView就是这样:
<Window x:Class="FileMerger.MainWindow"
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:local="clr-namespace:FileMerger"
xmlns:Views="clr-namespace:FileMerger.Views"
xmlns:ViewModels="clr-namespace:FileMerger.ViewModels"
mc:Ignorable="d"
Title="File Merge" Height="450" Width="800">
<Window.DataContext>
<ViewModels:MainViewModel></ViewModels:MainViewModel>
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModels:MergeListViewModel}">
<Views:MergeList/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:EditMergeViewModel}">
<Views:EditMergeView/>
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding CurrentPageViewModel}"></ContentControl>
</Window>
和MainViewModel如下:
public class MainViewModel:ViewModelBase
{
private ViewModelBase _currentPageViewModel;
private MergeListViewModel _mergeListViewModel=new MergeListViewModel();
private EditMergeViewModel _editMergeViewModel = new EditMergeViewModel();
public MainViewModel()
{
// Set starting page
_mergeListViewModel.MergeSelected += navToMergeEdit;
CurrentPageViewModel = _mergeListViewModel;
}
public ViewModelBase CurrentPageViewModel
{
get
{
return _currentPageViewModel;
}
set
{
if (_currentPageViewModel != value)
{
_currentPageViewModel = value;
RaisePropertyChanged(nameof(CurrentPageViewModel));
}
}
}
public void navToMergeEdit(int mergeId)
{
_editMergeViewModel.MergeId = mergeId;
CurrentPageViewModel = _editMergeViewModel;
}
}
我的第一个视图MergeListView在ViewModel(MergeListViewModel)中具有此事件
public event Action<int> MergeSelected = delegate { };
想法是,当选择“合并”时,将EditMergeView与ViewModel EditMergeViewModel一起加载,并传递mergeId作为参数。应该运行EditMergeViewModel中的LoadedCommand,它会获取数据以使用Merge填充ViewModel。
EditMergeView中的EventTrigger应该执行此操作:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<command:EventToCommand Command="{Binding LoadedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
虽然发现断点显示MainViewModel中的NavToMergeEdit是通过事件调用的,但我发现没有调用LoadedCommand。我在EditMergeView的构造函数中插入了一个断点,发现在调用InitializeComponent()之前,this.DataContext为null,而在InitializeComponent()之后则填充了它。我相信Loaded事件是在InitializeComponent()中触发的,但是此时未设置datacontext,这导致了问题。
这在VS的“输出”窗口中受到以下支持,这向我提示EditMergeView没有在正确的位置绑定到ViewModel
System.Windows.Data Error: 40 : BindingExpression path error: 'LoadedCommand' property not found on 'object' ''EditMergeViewModel' (HashCode=31475357)'. BindingExpression:Path=LoadedCommand; DataItem='EditMergeViewModel' (HashCode=31475357); target element is 'EventToCommand' (HashCode=41172271); target property is 'Command' (type 'ICommand')
Exception thrown: 'System.NullReferenceException' in FileMerger.exe
Exception thrown: 'System.Reflection.TargetInvocationException' in mscorlib.dll
System.Windows.Data Error: 17 : Cannot get 'MergeName' value (type 'String') from '' (type 'EditMergeViewModel'). BindingExpression:Path=MergeName; DataItem='EditMergeViewModel' (HashCode=31475357); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String') TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object.
at FileMerger.ViewModels.EditMergeViewModel.get_MergeName() in C:\Users\JonathanS\source\repos\FileMerger\FileMerger\ViewModels\EditMergeViewModel.cs:line 270
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
at MS.Internal.Data.PropertyPathWorker.GetValue(Object item, Int32 level)
at MS.Internal.Data.PropertyPathWorker.RawValue(Int32 k)'
System.Windows.Data Error: 40 : BindingExpression path error: 'EditMergeCommand' property not found on 'object' ''EditMergeViewModel' (HashCode=31475357)'. BindingExpression:Path=EditMergeCommand; DataItem='EditMergeViewModel' (HashCode=31475357); target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')
我在做什么错?我是否需要调用它并在View构造函数中创建ViewModel并在那里设置DataContext? 。也许不太优雅,但可以避免这种情况。
幸运的是我有一点时间来解决这个问题。在EditMergeViewModel中,我没有在命令的getter和setter中使用属性。例如,我有