从ViewModel打开/关闭视图

时间:2013-08-26 00:46:04

标签: c# wpf mvvm view viewmodel

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

以下是我目前的工作方式:

AddClientViewModel:

    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();
        }
    }

这是SuggestedAddressesView构造函数,其中AddClientViewModel从ViewModelBase继承

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

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

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

3 个答案:

答案 0 :(得分:5)

只要从VM引用UI元素(在本例中为View),就会违反建议的MVVM准则。只有这样我们才能知道在VM中创建Window对象是错误的。

现在纠正这个:

  • 首先尝试保持1个视图&lt; - &gt;您的应用程序中有1个VM。它更干净,允许您使用相同的逻辑轻松切换View实现。将多个View添加到同一个VM即使没有“突破性”也只会让它变得笨拙。
  • 所以现在你有AddClientViewSuggestedAddressesView拥有自己的VM。太好了!

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

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

使用“Messenger”方法处理查看打开

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

就是这样。现在,当AddClientViewModel想要显示SuggestedAddressesView时,它会向其自己的视图发送消息,而视图又会创建并显示SuggestedAddressesView。这样VM就不会引用任何View,我们会继续遵守MVVM标准。

使用“Messenger”方法处理查看关闭

  • 关闭View非常简单。再次当您需要从VM关闭View时,您会向其自己的View发送一条消息,要求将其关闭。
  • 收到此消息后,View几乎会通过.Hide() / .Close()关闭,或者您想要删除它。

在这个中,每个VM处理它自己的View关闭,你没有任何相互连接的依赖。

您可以使用this作为起点来指导您处理此方法的“消息”。它有一个附加的下载,你可以看到Messenger如何工作。这是MVVM Light,如果您不使用它或使用其他/您自己的MVVM实现,请将其用作指南以帮助您获得所需的内容。

答案 1 :(得分: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();
    }

答案 2 :(得分:-1)

从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);