我有一个按钮,我把这个按钮绑定到ViewModel中的一个命令,比如OpenWindowCommand
。当我点击按钮时,我想打开一个新窗口。但是创建一个窗口示例并从视图模型显示一个窗口是违反MVVM的。我创建了一个接口
interface IWindowService
{
void showWindow(object dataContext);
}
而WindowService
实现此接口,如
class WindowService : IWindowService
{
public void showWindow(object dataContext)
{
ChildWindow window=new ChildWindow();
window.DataContext=dataContext;
window.Show();
}
}
在这个类中,我指定了ChildWindow
。所以这个类与显示ChildWindow
紧密耦合。当我想显示另一个窗口时,我必须实现另一个具有相同接口和逻辑的类。我怎样才能使这个类成为泛型,这样我就可以只传递任何窗口的示例,而这个类将能够打开任何窗口?
我没有使用任何构建的MVVM框架。我读过很多关于StackOverflow的文章,但我找不到任何解决方案。
7条答案
按热度按时间7cwmlq891#
你说“创建窗口示例并从视图模型显示窗口违反了MVVM”。这是正确的。
您现在正在尝试创建一个接口,该接口采用VM指定的视图类型。这同样是一种侵犯。您可能已经抽象出了接口背后的创建逻辑,但您仍然在VM中请求视图创建。
VM应该只关心创建VM。如果您真的需要一个新窗口来托管新VM,那么就像您所做的那样提供一个界面,但是这个界面不接受视图。你为什么需要风景?大多数(VM优先)MVVM项目使用隐式数据模板将视图与特定VM相关联。VM对它们一无所知。
就像这样:
显然,您需要确保在app.xaml中设置了VM-> Viewimplicittemplates,这样才能正常工作。这只是标准的VM优先MVVM。
例如:
jgovgodb2#
一种可能性是具有以下内容:
然后你可以这样做:
有关新约束的更多信息,请参见http://msdn.microsoft.com/en-gb/library/sd2w2ew5.aspx
注意:
new() constraint
只在窗口有无参数构造函数的情况下工作(但我想在这种情况下这应该不是问题!)在更一般的情况下,请参阅Create instance of generic type?了解可能性。egdjgwm83#
你可以这样写一个函数:
确保ViewBase具有DataContext属性。(可以继承UserControl)
一般来说,我会创建某种消息总线,并让ViewManager监听请求视图的消息。ViewModels将发送一条消息,要求显示视图和数据。然后ViewManager将使用上面的代码。
为了防止调用ViewModel来了解视图类型,您可以将视图的字符串/逻辑名称传递给ViewManager,并让ViewManager将逻辑名称转换为类型。
gv8xihay4#
在绑定DataConext的窗口中使用contentpresenter。然后为您的DataContext定义一个Datatemplate,这样wpf就可以呈现您的DataContext。类似于DialogWindow Service
因此,您只需要一个带有ContentPresenter的ChildWindow:
iyzzxitl5#
我发现公认的解决方案非常有用,但在实际尝试时,我发现它缺乏使UserControl(VM -> ViewMap产生的视图)停靠在托管窗口内以占据其提供的整个区域的能力。因此,我扩展了解决方案,以包含以下功能:
这里的技巧是使用DockPanel来托管从VM转换的视图。
如果希望窗口的大小与其内容的大小相匹配,则可以使用前面的方法,如下所示:
或者,如果窗口的大小固定,则如下所示:
r9f1avp56#
也许你可以传递窗口类型。
尝试使用
Activator.CreateInstance()
。请参见以下问题:Instantiate an object with a runtime-determined type。
Chakrit的解决方案:
ccgok5k57#
这是一个小小的贡献。为了更通用,我们可以获取传递给showWindow方法的viewModel的类型,然后查找其对应的视图,最后将其示例化。
然后您可以在viewModel中调用它