这是使用 MVVM Light Messenger 类的确切情况。您将首先使用 VML 注册您的 Person View,就像您的 MainView 链接起来一样
将此添加到您的 ViewModelLocator 构造函数中:
SimpleIoc.Default.Register<PersonViewModel>();
在构造函数之外添加这个(使用片段 mvvmlocatorproperty):
/// <summary>
/// Gets the PersonView property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public PersonViewModel PersonView
{
get
{
return ServiceLocator.Current.GetInstance<PersonViewModel>();
}
}
并确保您的视图是这样连接的:
<Window x:Class="MvvmLight1.PersonView"
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:ignore="http://www.ignore.com"
mc:Ignorable="d ignore"
DataContext="{Binding PersonView, Source={StaticResource Locator}}">
现在,在 ListBox ItemTemplate 上将一个事件连接到 Command
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseUp">
<cmd:EventToCommand Command="{Binding OpenPersonCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
确保在 XAML 窗口声明中包含这两个命名空间:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
现在你们都可以使用定位器了。
至于消息传递,要打开一个新视图,您需要创建一个消息。下面是我的视图模型,后面我会解释
public class MainViewModel : ViewModelBase
{
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
OpenPersonCommand = new RelayCommand(() =>
{
Messenger.Default.Send<Person>(new Person() { FirstName = "Daryl" }, "OPENPERSONVIEW");
});
}
/// GOT THIS USING mvvminpc snippet
/// <summary>
/// The <see cref="OpenPersonCommand" /> property's name.
/// </summary>
public const string OpenPersonCommandPropertyName = "OpenPersonCommand";
private ICommand _openPersonCommand;
/// <summary>
/// Sets and gets the OpenPersonCommand property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public ICommand OpenPersonCommand
{
get
{
return _openPersonCommand;
}
set
{
if (_openPersonCommand == value)
{
return;
}
RaisePropertyChanging(OpenPersonCommandPropertyName);
_openPersonCommand = value;
RaisePropertyChanged(OpenPersonCommandPropertyName);
}
}
}
}
确保包含 GalaSoft.MvvmLight.Command、GalaSoft.MvvmLight.Messaging 以使其正常工作。您正在做的是向收到该类型消息(在本例中为 Person 对象)的任何人发送消息,并使用该确切令牌(在本例中,我的令牌是字符串“OPENPERSONVIEW”,第二个参数。我通常使用枚举数,但为了简单起见,这将起作用)。
现在,在 MainView.xaml 后面的代码中,在构造函数中添加:
Messenger.Default.Register<Person>(this, "OPENPERSONVIEW", (myPerson) =>
{
PersonView view = new PersonView();
view.ShowDialog();
Messenger.Default.Send<Person>(myPerson, "PASSVARIABLE");
});
我们所做的是我们已经注册接收通过 Person 对象传递的任何消息,并且具有“OPENPERSONVIEW”标记。一旦我们在后面的代码中收到该消息,我们将实例化一个新的 PersonView。一旦该人员视图被实例化,我们将使用我们的人员对象发送另一条消息,该消息只会由正在侦听令牌“PASSVARIABLE”的 Messenger 侦听器接收。
现在要将主视图模型的实际值获取到您的人视图模型中,您将使用另一个信使来接收使用令牌“PASSVARIABLE”发送的消息。在 PersonViewModel 的构造函数中,添加以下内容:
Messenger.Default.Register<Person>(this, "PASSVARIABLE", (myPerson) =>
{
ThisPerson = myPerson;
});
并确保在 View Model 中有一个名为 ThisPerson 的属性(使用来自 MVVM Light 的 mvvminpc 片段创建):
/// <summary>
/// The <see cref="ThisPerson" /> property's name.
/// </summary>
public const string ThisPersonPropertyName = "ThisPerson";
private Person _thisPerson;
/// <summary>
/// Sets and gets the ThisPerson property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public Person ThisPerson
{
get
{
return _thisPerson;
}
set
{
if (_thisPerson == value)
{
return;
}
RaisePropertyChanging(ThisPersonPropertyName);
_thisPerson = value;
RaisePropertyChanged(ThisPersonPropertyName);
}
}
基本上,我们所做的是使用 MVVM Light Messenger 类来传递数据,但它都是松散耦合的。注册的信使都不关心传递给他们的东西,或者从谁那里得到什么,他们只是在听他们的令牌,并按照他们的要求去做。
我知道这很长,但请发表评论,我将逐步解决您遇到问题的地方。我刚刚发现很多 MVVM Light 问题的答案只能说明一小部分,但不能说明全部情况。
还有其他方法可以做到这一点,但这是基本的 MVVM-Light 开箱即用方式。