在MVVM WPF中打开新窗口

DT *_*ant 39 c# wpf mvvm

我有Button,我已将此按钮绑定到ViewModel中的命令说OpenWindowCommand.当我点击按钮时,我想打开新窗口.但是创建窗口实例并从视图模型显示窗口违反了MVVM.我已经创建了界面

interface IWindowService
{
 void showWindow(object dataContext);
}
Run Code Online (Sandbox Code Playgroud)

和WindowService一样实现这个接口

class WindowService:IWindowService
{
 public void showWindow(object dataContext)
 {
  ChildWindow window=new ChildWindow();
  window.DataContext=dataContext;
  window.Show();
  }
}
Run Code Online (Sandbox Code Playgroud)

在这个课程中,我指定了ChildWindow.因此,这个类与显示ChildWindow紧密结合.当我想要显示另一个窗口时,我必须实现具有相同接口和逻辑的另一个类.如何使这个类通用,以便我可以传递任何窗口的实例,并且类将能够打开任何窗口?我没有使用任何构建的MVVM框架.我已经阅读了很多关于StackOverflow的文章,但我找不到任何解决方案.

Gaz*_*yer 44

你说"创建窗口实例并从视图模型显示窗口是违反MVVM".这是对的.

您现在正在尝试创建一个接口,该接口采用VM指定的视图类型.这也是一种违规行为.您可能已经抽象出了接口背后的创建逻辑,但您仍在从VM中请求视图创建.

VM应该只关心创建VM.如果您确实需要一个新窗口来托管新VM,那么请提供一个已完成的界面,但不提供视图的界面.你为什么需要这个观点?大多数(VM优先)MVVM项目使用隐式数据窗口将视图与特定VM相关联.VM对它们一无所知.

像这样:

class WindowService:IWindowService
{
    public void ShowWindow(object viewModel)
    {
        var win = new Window();
        win.Content = viewModel;
        win.Show();
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,您需要确保在app.xaml中设置VM-> View隐式模板才能使其正常工作.这只是标准的VM第一MVVM.

例如:

<Application x:Class="My.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="clr-namespace:My.App.ViewModels"
             xmlns:vw="clr-namespace:My.App.Views"
             StartupUri="MainWindow.xaml">
    <Application.Resources>

        <DataTemplate DataType="{x:Type vm:MyVM}">
            <vw:MyView/>
        </DataTemplate>

    </Application.Resources>
</Application>
Run Code Online (Sandbox Code Playgroud)

  • 我希望`vw:MyView`应该是`UserControl`类型而不是`Window`类型 (8认同)
  • 如果MyView是一个Window,此解决方案将无法工作.它会抛出"无法将窗口置于样式中"的错误 (5认同)
  • 为什么需要不同的窗口类型?窗口只是视图的容器。只需使用通用窗口并正常使用隐式 DataTemplates 来映射 VM-&gt;View (3认同)
  • 虚拟机对View一无所知的原因之一是因为您可以使用多个视图以不同方式在ViewModel中显示数据.此方法使您的视图和视图模型具有1:1映射. (3认同)
  • 我知道这是迟到的评论,但我同意@Gopichandar,因为当我将窗口添加到内容中时,它会抛出运行时异常“窗口必须是树的根。无法将窗口添加为 Visual 的子项” (2认同)
  • @LuckyLuke82听起来你正在将视图定义为窗口。它应该是一个用户控件。 (2认同)

Dav*_*d E 6

一种可能性是:

class WindowService:IWindowService
{
 public void showWindow<T>(object DataContext) where T: Window, new() 
 {
  ChildWindow window=new T();
  window.Datacontext=DataContext;
  window.show();
 }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以去像:

windowService.showWindow<Window3>(windowThreeDataContext);
Run Code Online (Sandbox Code Playgroud)

有关新约束的详细信息,请参阅http://msdn.microsoft.com/en-gb/library/sd2w2ew5.aspx

注意:new() constraint唯一的工作是窗口将具有无参数构造函数(但我想在这种情况下这应该不是问题!)在更一般的情况下,请参阅创建泛型类型的实例?为了可能性.

  • windowService.showWindow <Window3>(windowThreeDataContext); 这个语句在viewmodel中,它包含view的名称.它不是MVVM方法的紫罗兰吗? (7认同)