wpf 从 ViewModel 打开/关闭视图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18435173/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 09:29:54  来源:igfitidea点击:

Open/Close View from ViewModel

c#wpfmvvmviewviewmodel

提问by francisg3

I have an AddClientViewModel which is referenced by 2 views (AddClientView and SuggestedAddressesView). The AddClientView is a form which has a field for an address. The form has a validate button which validates the entered address using Geocoding. If more than one address is returned, the SuggestedAddressesView opens.

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

Here is how I am currently doing it:

这是我目前的做法:

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

Here is the SuggestedAddressesView constructor where AddClientViewModel inherits from ViewModelBase

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

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

The other problem I am having is when I call OnClosingRequest() from the AddClientViewModel...both the AddClientView and SuggestedAddressesView closes. I know this happens because both views reference the same ViewModel. This is not the behaviour I want. I would like to be able to independently close either Window.

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

Is opening a View from the ViewModel proper MVVM structure and how would I go about being able to close windows independently?

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

采纳答案by Viv

As soon as you refer to UI elements(In this case the View) from the VM, you're going against suggested MVVM Guidelines. With just that we can know creating the Windowobject in the VM is wrong.

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

So now onto rectifying this:

所以现在纠正这个:

  • Firstly try to keep a 1 View <-> 1 VM in your application. It's cleaner and allows you to switch out View implementations with the same logic very easily. Adding multiple View's to the same VM even if not "ground-breaking" just makes it clumsy.
  • So now you got AddClientViewand SuggestedAddressesViewwith their own VM. Great!
  • 首先尝试在您的应用程序中保留 1 View <-> 1 VM。它更简洁,并允许您非常轻松地切换具有相同逻辑的 View 实现。将多个视图添加到同一个虚拟机即使不是“开创性的”也只会让它变得笨拙。
  • 所以,现在你得到了AddClientView,并SuggestedAddressesView用自己的VM。伟大的!

Implementing a View Open/Close from the VM:

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

  • Since we cannot access the View directly from our VM(to comply with standards), we can use approaches such as using a Messenger(MVVM Light), EventAggregator(PRISM) and so on to send a "message" from the VM to the View when you need to open/close a View and do the actual operation in the View.
  • This way the VM just initiates the message and can be unit-tested fine for the same operation and does not reference any UI elements.
  • 由于我们不能直接从我们的 VM 访问视图(以符合标准),我们可以使用诸如使用Messenger(MVVM Light)、EventAggregator(PRISM)等方法从 VM 向视图发送“消息”,当您需要打开/关闭一个视图并在视图中进行实际操作。
  • 通过这种方式,VM 只是启动消息,并且可以对相同的操作进行良好的单元测试,并且不引用任何 UI 元素。

Using a "Messenger" approach to handle View open:

使用“Messenger”方法来处理 View open

  • As per your Logic, it is the AddClientViewModelwhich would have to ask for the SuggestedAddressesViewto be opened.
  • Thus when you detect SuggestedAddresses.Count > 0, you would send a message to the AddClientViewasking it to open up the SuggestedAddressesView.
  • In AddClientView.xaml.csupon receiving this message, you would do what you're currently doing in the VM. Create an object of SuggestedAddressesViewand call .Show()on it.
  • One extra step you would add in the above step's process is to assign the DataContextof SuggestedAddressesViewas SuggestedAddressesViewModel.
  • 根据您的逻辑,这是AddClientViewModel必须要求SuggestedAddressesView打开的。
  • 因此,当您检测到时SuggestedAddresses.Count > 0,您会向AddClientView它发送一条消息,要求它打开SuggestedAddressesView.
  • AddClientView.xaml.cs收到此消息时,你会做你正在做的VM什么。创建一个对象SuggestedAddressesView并调用.Show()它。
  • 您将在上述步骤的过程中添加的一个额外步骤是将DataContextof分配为SuggestedAddressesViewas SuggestedAddressesViewModel

That's it. Now what you have is, when AddClientViewModelwants SuggestedAddressesViewshown, it sends a message to it's own View and the View in-turn creates and shows the SuggestedAddressesView. This way the VM does not reference any View's and we keep to holding MVVM standards.

就是这样。现在,你有什么,当AddClientViewModel都想SuggestedAddressesView所示,将消息发送到它自己的观点和视角-以转创建和演出SuggestedAddressesView。这样 VM 就不会引用任何视图,我们继续保持 MVVM 标准。

Using a "Messenger" approach to handle View close:

使用“Messenger”方法来处理 View close

  • Closing a Viewis pretty simple. Again when you need to close the View from the VM, you send a message to it's own View asking for it to be closed.
  • On receiving this message, the View pretty much closes itself via .Hide()/ .Close()or however else you want to get rid of it.
  • 关闭 aView非常简单。同样,当您需要从 VM 关闭视图时,您可以向它自己的视图发送一条消息,要求将其关闭。
  • 收到此消息后,视图几乎会通过.Hide()/关闭自己,.Close()或者您想摆脱它。

In this each VM handles it's own View's closing and you don't have any inter-connected dependencies.

在这种情况下,每个 VM 处理它自己的 View 关闭,并且您没有任何相互连接的依赖项。

You can use thisas a start point to guide you in handling "messages" for this approach. it has an attached download you can get and see how the Messengerworks. This is with MVVM Light, if you do not use it or use something else/ your own MVVM implementation, use it as a guide to help get to what you need.

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

回答by Gul Md Ershad

To open window from ViewModel:

从 ViewModel 打开窗口:

Create NavigationService.cs class for opening window: Let NavigationService.cs

创建用于打开窗口的 NavigationService.cs 类:让 NavigationService.cs

Now put following code in that class file.

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

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

then. Create instance of NavigationService.cs class MainWindowViewModel file. Then

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

Window1ViewModel window1ViewModel = new Vindow1ViewModel();
window1ViewModel.Name = MainWindowTextValue;
NavigationService navigationService = new NavigationService();
navigationService.ShowWindow1Screen(window1ViewModel);

回答by Krish

you can use RelayCommand so that you send the parameter as follows:

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

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

By using this you can close the individual views.

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

Example:

例子:

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

public void OnClose(object param)
    {
       AddClientView/SuggestedAddressesView Obj = param as AddClientView/SuggestedAddressesView;
       obj.Close();
    }