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

时间:2016-05-18 08:29:06

标签: c# wpf xaml mvvm

我正在学习WPF MVVM并希望在主窗口点击按钮时打开一个新窗口。

我知道每个View都必须有一个等效的ViewModel,而MVVM的基本原则之一就是ViewModel一定不能了解View。

因此,任何人都可以向我提供一个简单的简洁示例,该示例不违反任何MVVM原则,如何创建两个具有以下功能的View和两个ViewModel:

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

6 个答案:

答案 0 :(得分:1)

您可以创建单独的服务以将视图作为对话框启动,以便可以在整个应用程序中以通用方式使用它。并将通过想要启动任何对话框的构造函数将此服务注入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();
    }
}

您可以创建单独的服务以将视图作为对话框启动,以便可以在整个应用程序中以通用方式使用它。并将通过想要启动任何对话框的构造函数将此服务注入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();
    }
}

现在只需将此服务注入相应的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();
    }
}

您可以使用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>

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

Window.DataContext是ViewModelB的一个实例,然后将显示ViewB。

我见过并阅读过的最好的例子是由Rachel Lim制作的。 See the example.

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:0)

我过去取得的一些成功所做的就是创建一个基本上是View Factory的东西,构建一个视图并为它指定一个视图模型。这给了我一个一站式的商店来做意见,就像你使用IoC一样。

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

答案 3 :(得分:0)

Window newWindow = new Window();
Window.Show(); 

或者如果要禁用上一个窗口

Window newWindow = new Window();
Window.ShowDialog();

答案 4 :(得分:0)

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

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

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

而且...当然...您的viewmodel首先要传递的参数是。因此,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();
    }
 }

答案 5 :(得分:-2)

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

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

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

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