我试图让我的WPF应用程序解耦,因此我做了类似的事情:
视图项目。
ViewModel项目。
在mainwindow
中,我在一个位于ViewModel DLL中的OpenChildWindowCommand
按钮之间进行了绑定。
OpenChildWindowCommand
继承自ICommand
,并在OpenChildWindow
中执行对MainViewModel
方法的调用。
现在问题是ViewModel
不知道ChildWindow
,因为它是一个不同的DLL。
我要问的是:最好的方法是什么 - 将打开子窗口?
也许他们之间会有某种消息传递。
答案 0 :(得分:1)
首先,我祝贺你将你的观点与观点模型分开 - 将它们保持在同一个集合中会导致很多人采取他们不应该做的捷径。
使用按钮绑定,我建议您将命令代码放在视图后面的代码中。它是与视图的交互导致子窗口被打开,因此从根本上没有理由为什么命令代码需要在viewmodel中。您的代码将如下所示:
public ICommand OpenChildWindowCommand
{
get
{
return new DelegateCommand<object>(ExecuteOpenChildWindowCommand, CanOpenChildWindowCommandExecute);
}
}
private void ExecuteOpenChildWindowCommand(object context)
{
...code to open the child window...
}
private void CanOpenChildWindowCommandExecute(object context)
{
return true;
}
(DelegateCommand<T>
来自Microsoft的PRISM库)。您的XAML将如下所示:
<Button x:Name="MyButtonName"
Command="{Binding OpenChildWindowCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
/>
我建议你做的是开始使用对话服务 - 这是一些与对话框相关的代码,它被抽象成一个独立的帮助式服务。进入对话框服务的细节会使这个答案有点长,所以这里有一些有用的链接可以帮助你入门:
如果你将新的对话服务与使用IoC容器结合起来,那么你可以得到一些非常好的解耦MVVM和测试友好代码,如下所示:
public class MyMainWindow
{
private IDialogService dialogService;
public MyMainWindow(IUnityContainer container)
{
dialogService = container.Resolve<IDialogService>();
}
private void ExecuteOpenChildWindowCommand(object context)
{
var dlg = _dialogService.Show<IMyDialogWindow>();
}
}
(初始化容器并在应用程序启动的早期将接口注册到具体的类映射)。
答案 1 :(得分:0)
使用 EventAggregator 进行两个模块之间的通信。
答案 2 :(得分:0)
我不确定您是否在您的应用程序中使用任何特定框架,但即使您不是,请从Microsoft's Prism framework和MSDN Prism documentation获取提示。具体来说,请查看高级部分用户交互模式:
基本上,您只需在视图模型上创建交互请求,其中交互的结果将通过回调委托传递。
通常,这些是MessageBox的简单替换,但我已经将此模式用于更复杂的场景,例如年龄验证,确认框(是/否),甚至是要求提供姓名和地址的整个屏幕。
你的问题没有真正简单的答案,因为它实际上取决于你在做什么......但过去我用MEF加载模块,而EventAggregator / Container用来获取Modal的内容视窗。
实际上,最后您的主ViewModel使用界面来启动交互,框架的其他组件创建弹出窗口,加载内容并完成交互。一直以来,视图模型都不知道窗口或弹出窗口或其他任何视图模型和有效负载类。这意味着一切都可以毫无问题地进行单元测试。