1

最新的 MVVM Light 工具包使用 ViewModelLocator (VML) 中的 IoC 来提供 ViewModel 的实例。

这些实例由只读实例属性提供(即非静态)

示例显示了从 VML 公开的 MainViewModel,但不是父视图子视图

我的主视图正在查看 MainViewModel 公开的人员列表。

在主视图中点击其中一个人员项目时,我想导航到 PersonView。该 PersonView 将绑定到 PersonViewModel。

PersonViewModel 会从 VML 中暴露出来吗?如果是这样,MainViewModel 会做什么来传达对 PersonViewModel 的点击?它不能在 VML 中设置 PersonViewModel,因为该属性只是一个 Get。

我过去使用过 MVVM Light,并在 VML 上使用过 Ready Write 属性

4

1 回答 1

0

这是使用 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 开箱即用方式。

于 2013-09-25T00:29:19.157 回答