在WPF中使用MVVM模式创建对话框时,如何实例化对话框并记录用户输入

时间:2019-06-27 07:02:38

标签: c# wpf mvvm

我是C ++开发人员,是WPF和MVVM的新手。如果我选择了错误的单词来问我的问题,请忍受我

我在 MFC / C ++ 中有我的Main应用程序,该应用程序将一些数据传递到C#库中( CLI 被用作中间层)。 在 C#库中,有一段代码打开了一个对话框,填充了数据,并通过以下方式将用户选择通知给调用对象-

public classA()
{
    MyDialog dlg = new MyDialog(param1, param2, param3)
    if(dlg.ShowDialog().GetValueOrDefault())
    {
        var name = dlg.name;
        var roll = dlg.roll;
    }
    else
    {
        var name = string.Empty;
        var roll = string.Empty;
    }
}

现在,对话框已使用 MVVM 模式进行了修改和实现。

作为实现的一部分,我创建了以下文件- 1

  1. MyDialogView.Xaml
  2. MyDialogView.xaml.cs
  3. MyDialogViewModel.cs
  4. MyDialogModel.cs

我的问题是,如何现在从我的 classA 实例化新对话框,以便使用传递给对话框的参数以与以前相同的方式填充数据,并记录用户选择而不会丢失任何内容数据并安全地关闭视图。

2 个答案:

答案 0 :(得分:2)

标准MVVM方法的工作方式如下(至少在使用MVVM Light时):

  1. 您有一个VM层,一个类库。
  2. 您有一个View层,一个WPF控件库或WPF应用程序。
  3. 视图层添加对VM层的引用。 VM层对View一无所知。
  4. 您为对话框的VM创建普通的公共类。称为DialogVM或其他名称。确保此类继承自MVVM Light的内置ViewModelBase。这将使您能够访问MVVM Light提供的更改通知方法。在您的情况下,可能看起来像这样:

    public partial class DialogVM : ViewModelBase
    {
        private string _Name;
        public string Name
        {
          get { return _Name; }
          set { Set(ref _Name, value); }
        }
    
        private string _Roll;
        public string Roll
        {
          get { return _Roll; }
          set { Set(ref _Roll, value); }
        }
    }
    
  5. VM层具有一个名为ViewModelLocator的全局静态类。此类执行IoC / DI,并提供公共静态属性以公开不同的VM。 (在您的情况下,对话框的VM转到VM项目,而ViewModelLocator看起来像这样:

    using System;
    
    namespace VMLayer
    {
      public class ViewModelLocator
      {
        static ViewModelLocator()
        {
          SimpleIoc.Default.Register<DialogVM>(true);
        }
    
        public static DialogVM MyDialog => SimpleIoc.Default.GetInstance<DialogVM>();
      }
    }
    
  6. 您的对话框(Window)转到“视图”层,并使用此公开属性MyDialog为对话框提供DataContext

    <Window x:Class="GlasshouseTestingShell.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:vm="clr-namespace:VMLayer;assembly=VMLayer"
        DataContext="{x:Static vm:ViewModelLocator.MyDialog}"
        d:DataContext="{d:DesignInstance Type=vm:DialogVM}">
    </Window>
    
  7. 看看我们在没有在View层中编写C#代码的情况下创建View层的DataContext的程度如何。从Binding表达式和其他地方获得所有设计时Intellisense的角度来看,这也很优雅。
  8. 您现在将所有UI内容(文本框,按钮等)绑定到对话框VM公开的公共属性和命令。后面的代码中仍然没有一行。在您的情况下,可能看起来像这样:

    <TextBox Text="{Binding Name}" />
    

其余的都是C ++:

  1. 您可以在C ++项目中添加对View和VM DLL的引用。
  2. 创建对话框的对象。它将自动实例化其VM并执行绑定。您调用ShowDialog()将其显示在屏幕上。
  3. “使用”在对话框中执行操作,最后按“确定”或“取消”。
  4. 您捕获对话框结果,然后访问对话框对象的DataContext属性,该属性是DialogVM类的对象。绑定已在VM中为您更新了这些属性,因此您可以从中访问用户提供的值。

答案 1 :(得分:1)

我不确定我是否会遵循您的所有要求,但这大致就是我将要完成的任务的方式:

实例化类A中的视图和视图模型。

设置所需的视图模型参数。作为属性或通过构造函数注入。

将视图的数据上下文设置为视图模型。

所有需要绑定的东西都应该在它们之间绑定。

显示视图视图。

用户在视图中进行编辑,更改仍保留在视图模型属性中。

它们完成编辑,然后您可以使用viewmodel属性。也许其中之一就是您提到的模型。也许是由视图模型实例化模型以获取数据,或者如果更方便,则由classA实例化。在后一种情况下,您可能必须将该模型传递给viewmodel。

请牢记以上内容。

一些粗糙的代码:

public class ClassA
{
    MyDialogViewModel vm = new MyDialogViewModel { Name = "X", Roll = "Y" };
    MyDialog dlg = new MyDialog();
    dlg.ShowDialog();
    var name = vm.Name;
    var roll = vm.roll;

    // Do something to persist your data as necessary. Either here or in a model within the viewmodel
}

名称和滚动可能绑定到视图中的某些文本框或某些文本属性。

如果只是获取两个字符串值那么简单,那么实际上拥有一个模型就没有任何好处。另一方面,如果更多地涉及处理,那么视图模型当然可以实例化模型。

MyDialogViewModel应该实现inotifypropertychanged,并且您需要绑定的任何东西都应该是一个公共属性。不知道您是否需要属性更改通知,但始终执行它。可以选择从属性设置者处更改属性。