在按钮上打开一个新窗口单击 WPF MVVM

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37294152/
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 13:49:01  来源:igfitidea点击:

Opening a new window on button click WPF MVVM

c#wpfxamlmvvm

提问by whitefang1993

I am learning WPF MVVM and want to open a new window on a button click from a main window.

我正在学习 WPF MVVM 并希望通过单击主窗口中的按钮打开一个新窗口。

I know each View has to have an equivalent ViewModel and one of the basic principles of MVVM is that the ViewModel must not know anything about the View.

我知道每个 View 都必须有一个等效的 ViewModel,而 MVVM 的基本原则之一是 ViewModel 不得了解有关 View 的任何信息。

So please can anybody provide me a simple clean example that does not violate any MVVM principles on how to create two Views and two ViewModels that have the following functionality:

所以请任何人都可以给我提供一个简单干净的示例,该示例不违反关于如何创建具有以下功能的两个视图和两个视图模型的任何 MVVM 原则:

Show a new view by clicking a button from a main View.

通过单击主视图中的按钮显示新视图。

回答by StepUp

You can create a separate service for launching views as dialog so that it can be used in a generic way across the application. And will inject this service to the ViewModel via Constructor which wants to launch any dialog.

您可以创建一个单独的服务以将视图作为对话框启动,以便它可以在整个应用程序中以通用方式使用。并将通过想要启动任何对话框的构造函数将此服务注入到 ViewModel。

public interface IDialogWindowService<T>
{
    void Show();
    void ShowDialog();
}

public class DialogWindowService<T> : IDialogWindowService<T> where T : Window
{
    public void Show()
    {
        container.Resolve<T>().Show();
    }

    public void ShowDialog()
    {
        container.Resolve<T>().ShowDialog();
    }
}

Now just inject this service to the respective ViewModel.

现在只需将此服务注入相应的 ViewModel。

public class YourViewModel
{
    //commands
    public ICommand someCommand { get; set; }

    private IDialogWindowService<BookingView> _dialogService;
    public YourViewModel(IDialogWindowService<YourView > dialogService)
    {
        _dialogService = dialogService
        someCommand = new RelayCommand(someCommandDoJob, () => true);
    }

    public void someCommandDoJob(object obj)
    {
        //Since you want to launch this view as dialog you can set its datacontext in its own constructor.    
        _dialogService.ShowDialog();
    }
}

OR

或者

you can use DataTemplatesto change view. It allows to dynamically switch Viewsdepending on the ViewModel:

你可以DataTemplates用来改变视图。它允许动态地切换Views取决于ViewModel

<Window>
   <Window.Resources>
      <DataTemplate DataType="{x:Type ViewModelA}">
         <localControls:ViewAUserControl/>
      </DataTemplate>
      <DataTemplate DataType="{x:Type ViewModelB}">
         <localControls:ViewBUserControl/>
      </DataTemplate>
   <Window.Resources>
  <ContentPresenter Content="{Binding CurrentView}"/>
</Window>

If Window.DataContext is an instance of ViewModelA, then ViewA will be displayed and

如果 Window.DataContext 是 ViewModelA 的实例,则将显示 ViewA 并

Window.DataContext is an instance of ViewModelB, then ViewB will be displayed.

Window.DataContext 是ViewModelB 的一个实例,那么就会显示ViewB。

The best example I've ever seen and read it is made by Rachel Lim. See the example.

我见过和读过的最好的例子是 Rachel Lim 制作的。请参阅示例。

回答by Mike Eason

Depending on your usage, there isn't anything wrong with opening a view from the view's code-behind. It's still view codeafter all.

根据您的使用情况,从视图的代码隐藏打开视图没有任何问题。毕竟它仍然是视图代码

MyView view = new MyView();
view.Show();

Otherwise, if you need to open a window from the ViewModelor using a ICommand, then you can look at the "Open Windows and Dialogs in MVVM"library I wrote on GitHub. This will demonstrate how to open a Windowby clicking on a button using the MVVM design pattern.

否则,如果您需要从ViewModel或 使用 a打开一个窗口ICommand,那么您可以查看我在GitHub 上写的“在 MVVM 中打开 Windows 和对话框”库。这将演示如何使用 MVVM 设计模式通过单击按钮来打开一个。Window

回答by Pedro G. Dias

What I've done with some success in the past is to create what is basically a View Factory, that constructs a view and assigns it a viewmodel. This gives me a one-stop shop to do the stiching for the views, much like you would to using IoC.

我过去取得的一些成功是创建了一个基本上是视图工厂的东西,它构建了一个视图并为其分配了一个视图模型。这为我提供了一个一站式服务来为视图进行拼接,就像使用 IoC 一样。

There may be advantages and disadvantages to this, so I'd be curious to learn if there are other/better ways, but so far, this is the practice I've found least painful.

这可能有优点和缺点,所以我很想知道是否有其他/更好的方法,但到目前为止,这是我发现最不痛苦的做法。

回答by SASS_Shooter

To be a more pure implementation of MVVM you can use a factory or have an interface-driven controller written for each view that handles a) what to show and b) how to bind it to the data. So for the controller : FormAlpha has FormAlphaViewModel and FormAlpha.VPS. The interface is perfect for this since every implementation is different.

要成为 MVVM 的更纯粹的实现,您可以使用工厂或为每个视图编写一个接口驱动的控制器,该控制器处理 a) 要显示的内容和 b) 如何将其绑定到数据。所以对于控制器:FormAlpha 有 FormAlphaViewModel 和 FormAlpha.VPS。该接口非常适合此,因为每个实现都不同。

So create a standard that each view had an interface-driven class that ends with vps - or visual presentation service. And you want to trigger FormAlpha on that button click. You would use reflection or factory to load FormAlpha.vps as an IVisualPresentor and call IVisualPrentor.Display(parms);

因此,创建一个标准,每个视图都有一个以 vps 结尾的界面驱动类 - 或视觉呈现服务。并且您想在单击该按钮时触发 FormAlpha。您将使用反射或工厂将 FormAlpha.vps 作为 IVisualPresentor 加载并调用 IVisualPrentor.Display(parms);

Each VPS has the job of loading a specific form, binding the databinding with the view model associated with that form (which not many solutions provided), and the first parameter always has a required parameter of Show() or ShowDialog().

每个 VPS 都有加载特定表单的工作,将数据绑定与与该表单关联的视图模型绑定(提供的解决方案不多),并且第一个参数始终具有 Show() 或 ShowDialog() 的必需参数。

And...of course...the first thing your viewmodel gets are the parameters passed. So VPS will break out those parameters and confirm that the correct parameters were passed. In this way (from your example) you have a function that the button represents and wants to deploy. The VPS handles the data and visuals needed to accomplish that. The caller just knows that the VPS will hand whatever that function is. Now I just rattled the code below from memory so it isn't perfect. But presents the thoughts I'm talking about above.

而且......当然......你的视图模型得到的第一件事是传递的参数。所以VPS会打断那些参数,并确认传递了正确的参数。通过这种方式(从您的示例中),您有一个按钮代表并想要部署的功能。VPS 处理完成此任务所需的数据和视觉效果。调用者只知道 VPS 将处理该功能是什么。现在我只是从记忆中乱写下面的代码,所以它并不完美。但提出了我在上面谈论的想法。

public interface IVisualPresentor
{ void Display(params object[] parms) };

public class FormAlpha.VPS : IVisualPresentor
{  
     public void Display(params object[] parms)
     {
       //validate parms if needed and cast to type specific data
       //for example it needs session data parms[1] and customer parms[2]
       var form = new FormAlpha();
       var model = new FormAlphaViewModel( sessionData, customer );
       form.DataBinding = model;
       if ((bool)parms[0])
          form.Show(); 
       else 
          form.ShowDialog();
    }
 }

回答by Dabuleanu Catalin

Let's say that Form1 is your main form,and Form2 is the one you want to open: You can use this code(insert it into Form1):

假设 Form1 是您的主表单,而 Form2 是您要打开的表单:您可以使用以下代码(将其插入 Form1):

Form2 frm = new Form2();
frm.Show();

Also if you want to close the main form you can use this.Close();(it will close current form). Furthermore if you want just to open Form2 but still Form1 to be the main one you can use:

此外,如果您想关闭可以使用的主表单this.Close();(它将关闭当前表单)。此外,如果您只想打开 Form2 但仍将 Form1 作为主要的,您可以使用:

Form2 frm = new Form2();
frm.Show();
this.Focus();