6

我有一个被 2 个视图(AddClientView 和 SuggestedAddressesView)引用的 AddClientViewModel。AddClientView 是一个包含地址字段的表单。该表单有一个验证按钮,该按钮使用地理编码验证输入的地址。如果返回多个地址,则会打开 SuggestedAddressesView。

这是我目前的做法:

添加客户端视图模型:

    private void ValidateExecute(object obj)
    {
        SuggestedAddresses = new ObservableCollection<DBHelper.GeocodeService.GeocodeResult>(GeoCodeTest.SuggestedAddress(FormattedAddress));

        ....

        if (SuggestedAddresses.Count > 0)
        {
            var window = new SuggestedAddressesView(this);
            window.DataContext = this;
            window.Show();
        }
    }

这是 AddClientViewModel 从 ViewModelBase 继承的 SuggestedAddressesView 构造函数

    public SuggestedAddressesView(ViewModelBase viewModel)
    {
        InitializeComponent();
        viewModel.ClosingRequest += (sender, e) => this.Close();
    }

我遇到的另一个问题是当我从 AddClientViewModel 调用 OnClosingRequest() 时……AddClientView 和 SuggestedAddressesView 都关闭了。我知道会发生这种情况,因为两个视图都引用了相同的 ViewModel。这不是我想要的行为。我希望能够独立关闭任一窗口。

是否从 ViewModel 正确的 MVVM 结构打开视图,我将如何能够独立关闭窗口?

4

3 回答 3

5

一旦您从 VM 中引用 UI 元素(在本例中为视图),您就会违反建议的 MVVM 指南。这样我们就可以知道Window在 VM 中创建对象是错误的。

所以现在开始纠正这个问题:

  • 首先尝试在您的应用程序中保留 1 View <-> 1 VM。它更简洁,允许您非常轻松地切换具有相同逻辑的 View 实现。将多个视图添加到同一个虚拟机即使不是“开创性的”,也只会让它变得笨拙。
  • 所以现在你有了自己的虚拟机AddClientViewSuggestedAddressesView伟大的!

从 VM 实现视图打开/关闭:

  • 由于我们不能直接从我们的 VM 访问 View(为了符合标准),我们可以使用诸如使用Messenger(MVVM Light)、EventAggregator(PRISM)等的方法,当您从 VM 向 View 发送“消息”时需要打开/关闭一个视图并在视图中进行实际操作。
  • 这样,VM 只是启动消息,并且可以针对相同的操作进行单元测试,并且不引用任何 UI 元素。

使用“Messenger”方法处理 View open

  • 根据您的逻辑,它AddClientViewModel必须要求SuggestedAddressesView打开。
  • 因此,当您检测到时SuggestedAddresses.Count > 0,您会发送一条消息AddClientView要求它打开SuggestedAddressesView
  • AddClientView.xaml.cs收到此消息后,您将执行当前在 VM 中执行的操作。创建一个对象SuggestedAddressesView并调用.Show() 它。
  • 您将在上述步骤的过程中添加的一个额外步骤是将DataContextof分配SuggestedAddressesViewSuggestedAddressesViewModel

而已。现在你所拥有的是,当需要显示时,它AddClientViewModelSuggestedAddressesView向它自己的视图发送一条消息,然后视图会创建并显示SuggestedAddressesView. 通过这种方式,VM 不会引用任何 View,并且我们继续保持 MVVM 标准。

使用“Messenger”方法处理 View close

  • 关闭 aView非常简单。同样,当您需要从 VM 关闭视图时,您会向它自己的视图发送一条消息,要求将其关闭。
  • 收到此消息后,视图几乎会通过.Hide()/自行关闭,.Close()或者您想摆脱它。

在此每个 VM 处理它自己的视图的关闭,并且您没有任何相互连接的依赖项。

您可以以此为起点来指导您处理此方法的“消息”。它有一个附件下载,您可以获取并查看其Messenger工作原理。这适用于 MVVM Light,如果您不使用它或使用其他东西/您自己的 MVVM 实现,请将其用作帮助获得所需内容的指南。

于 2013-08-26T09:05:46.453 回答
0

您可以使用 RelayCommand 发送参数,如下所示:

Command="{Binding CloseWindowCommand, Mode=OneWay}" 
CommandParameter="{Binding ElementName=TestWindow}"

通过使用它,您可以关闭各个视图。

例子:

public ICommand CloseCommand
    {
        get
        {
            return new RelayCommand(OnClose, IsEnable);
        }
    }

public void OnClose(object param)
    {
       AddClientView/SuggestedAddressesView Obj = param as AddClientView/SuggestedAddressesView;
       obj.Close();
    }
于 2013-08-26T08:59:35.970 回答
0

从 ViewModel 打开窗口:

为打开窗口创建 NavigationService.cs 类:让 NavigationService.cs

现在将以下代码放入该类文件中。

   public void ShowWindow1Screen(Window1ViewModel window1ViewModel)
       {
           Window1= new Window1();
           Window1.DataContext = window1ViewModel;
           Window1.Owner = Window1View;
           Window1.ShowDialog();
       }

然后。创建 NavigationService.cs 类 MainWindowViewModel 文件的实例。然后

Window1ViewModel window1ViewModel = new Vindow1ViewModel();
window1ViewModel.Name = MainWindowTextValue;
NavigationService navigationService = new NavigationService();
navigationService.ShowWindow1Screen(window1ViewModel);
于 2015-05-13T08:50:52.233 回答