【问题标题】:MVVM Light: how to send a parameter to ViewModel (when opening new window)?MVVM Light:如何向 ViewModel 发送参数(打开新窗口时)?
【发布时间】:2013-07-26 23:18:12
【问题描述】:

我正在尝试在 WPF 中使用 MVVM Light Toolkit 来学习 MVVM。但我被困在一个简单的问题上。

我有一个 AddEditProfileWindow,它基本上有一个配置文件名称的文本框和一个确认按钮。它将新配置文件添加到数据库表或更新现有配置文件的名称。

在 MainWindow/MainViewModel 我有一个配置文件列表和两个按钮:“添加配置文件”和“编辑选定配置文件”。他们都通过命令+消息打开这个窗口。例如这里是“添加配置文件”按钮的命令

    public RelayCommand OpenAddProfileWindowCommand
    {
        get
        {
            return _openAddProfileWindowCommand ?? (_openAddProfileWindowCommand = new RelayCommand(
                () => { Messenger.Default.Send(new NotificationMessage("OpenAddProfile")); }));
        }
    }

它是 MainWindow 代码后面的接收器

private void MessageReceived(NotificationMessage msg)
{
    if (msg.Notification == "OpenAddProfile")
    {
        var window = new AddEditProfileWindow();
        window.Owner = this;
        window.ShowDialog();
    }
}

所以问题是我需要以某种方式将参数传递给 AddEdit... Window/ViewModel(例如在 ViewModel 中设置 IsEditing bool 属性)以更改窗口行为并对其进行一些自定义(更改标题和确认按钮文本到“添加”或“更新”)。另外为了更新我需要所选记录的 Profile 对象(或至少是 Id)。

为了创建 ViewModel,我使用 ViewModelLocator 和 Unity

    public ViewModelLocator()
    {
        var container = new UnityContainer();

        ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));

        container.RegisterType<MainViewModel>(new ContainerControlledLifetimeManager()); // singleton
        container.RegisterType<AddEditProfileViewModel>(); 
    } 

    public AddEditProfileViewModel AddEditProfile
    {
        get
        { return ServiceLocator.Current.GetInstance<AddEditProfileViewModel>();  }
    }

我已经阅读了很多类似的线程和示例,但仍然不明白我应该如何将参数传递给视图模型。一些答案建议在应用程序启动时在 ViewModelLocator 中创建视图模型(并使它们成为单例),然后我可以在打开之前发送消息。但看起来不是很干净,而且我需要在打开之前重置视图模型(可能通过 Cleanup())。

有没有更好/更简单/更清洁的方法?

【问题讨论】:

    标签: wpf mvvm mvvm-light


    【解决方案1】:

    在我看来,Messenger 和从 IoC 获取 AddEditProfileViewModel 不适合这种情况。首先,您将消息从 UI 的 DataContext 发送到 UI。 Messenger 在松散耦合的组件之间工作,通常在同一级别,例如视图模型和视图模型。如果您希望视图模型通知视图,您可以使用 Prism 的 InteractionRequest。其次,AddEditProfileViewModel 可以被认为是一个临时的,基于它的视图是一个模态对话框,所以它的创建可能取决于创建它的环境。

    一种方法,使用共享服务,可能称为 IDialogService,它有一个方法可能称为 ShowAddEditDialog。您的主视图模型从 IoC 获取此服务,并在执行命令时调用它,添加/编辑。调用该方法时,主视图模型也会创建 AddEditProfileViewModel 并传递状态,例如添加/编辑、现有配置文件等。

    如果您仍想保留 Messenger 和 IoC,则使用应用程序控制器的另一种方法。你仍然可以在这里使用 Messenger,但监听消息的不是视图,而是应用程序控制器。现在,应用程序控制器、主视图模型、AddEditProfileViewModel 和 AddEdit 窗口都从 IoC 容器中解析。应用程序控制器拥有两个视图模型并监听消息。当它从主视图模型得到消息时,它会更新 AddEditProfileViewModel 上的状态,解析对话框,设置 DataContext 并显示对话框。您可以将应用程序控制器实例放在 MainWindow 代码后面或任何地方,因为一旦它从 IoC 得到解析,它就是自治的。

    【讨论】:

    • 关于 IoC,实际上我使用 IoC 只是因为 ViewModelLocator 默认情况下在 MVVM Light 中(它作为全局资源添加到 App.xaml 并且所有视图都使用像 DataContext="{Binding Source= 这样的绑定{静态资源定位器},路径=主要}">)。我没有使用 IoC 的经验,所以现在使用它并没有真正的好处。
    • 通常(在非 MVVM 应用程序、旧 WinForms 等中)我使用 WindowStartupLocation="CenterOwner" 并在后面的主窗口代码中创建新窗口时设置 window.Owner = this。据我了解,您是第一种方法,在这里不可能做类似的事情?因为 ViewModel 不应该对 View 有任何了解。
    猜你喜欢
    • 1970-01-01
    • 2015-03-03
    • 2011-03-24
    • 2012-12-21
    • 2012-07-12
    • 2017-06-24
    • 2011-05-27
    • 1970-01-01
    • 2014-11-08
    相关资源
    最近更新 更多