这是我的第一个WPF-MVVM
应用程序,这是我的结构:
- 我的一个项目
app.xaml
打开应用程序,并覆盖OnStartup
解决的主窗口。 (我这样做,由于参考); - 对于我的观点的一个项目;
- 我的ViewModels一个项目;
- 为我示范工程之一。
而且我去下面的问题:我在MainWindowView
和我点击一个按钮来显示另一种观点。 我应该怎么做,从我打开这个另一种观点认为MainWindowViewModel
而我View Project
具有参考ViewModel Project
,我不能引用ViewModel Project
与View Project
?
顺便说一句,我使用Unity
的dependency injection
。
所以,你能帮助我吗?
有几种方法了这一点。
您可以定义一个对话框/导航/窗口服务界面,在项目中的ViewModels定义。 您将需要决定的ViewModels将如何表达自己想打开的窗口。 我一般用的IDialogViewModel接口,其中一些我的ViewModels的实施,并通过视图模型的实例来服务,但您可以使用一个枚举,字符串,任何你想要的,这样您的实施可以映射到真正的窗口,这将是打开。
例如:
public interface IDialogService
{
bool? ShowDialog(object dialogViewModel);
}
希望打开新窗口的ViewModels将收到服务的实例,并用它来表示打开窗口的意图。 在你浏览的项目,你会定义一个实现你的服务接口,背后打开窗口中的真正的逻辑类型。
继例如:
public class DialogService : IDialogService
{
private Stack<Window> windowStack = new Stack<Window>();
public DialogService(Window root)
{
this.windowStack.Push(root);
}
public bool? ShowDialog(object dialogViewModel)
{
Window dialog = MapWindow(dialogViewModel);
dialog.DataContext = dialogViewModel;
dialog.Owner = this.windowStack.Peek();
this.windowStack.Push(dialog);
bool? result;
try
{
result = dialog.ShowDialog();
}
finally
{
this.windowStack.Pop();
}
return result;
}
}
你的主要项目将负责创建和注射在谁需要它的ViewModels对话服务。 在这个例子中,应用程序将创建传递主窗口给它一个新的对话框服务实例。
一种类似的方法做到这一点将使用某种形式的消息传递图案(的LINK1 LINK2 )。 此外,如果你想要的东西简单,你也可以让你的ViewModels引发事件时,他们要打开的窗口,让浏览订阅。
编辑
我在我的应用程序通常更复杂一点用,但这个想法基本上是一个完整的解决方案。 我有一个基地DialogWindow,一个希望将视图模型,它实现一个IDialogViewModel接口的DataContext。 这个接口抽象一些功能,你在对话框中预计,如接受/取消指令,以及一个封闭的事件,所以你也可以关闭从视图模型的窗口。 所述DialogWindow基本上由在其中的内容属性绑定到DataContext并钩住时DataContext的改变时,关闭事件(和其他一些东西)一个ContentPresenter。
每个“对话框中的”包括在IDialogViewModel和相关视图(用户控件)。 要映射它们,我只是宣布在App的资源隐含的DataTemplates。 在我展示的代码中,唯一的区别是不会有一个方法MapWindow,窗口实例将始终是一个DialogWindow。
我使用一个额外的招重用对话之间布局元素。 在做法是将它们包括在DialogWindow(接受/取消按钮等)。 我喜欢保持DialogWindow干净(所以我可以用它事件“非对话框”对话框)。 我宣布一个模板与常见的界面元素ContentControl中,当我宣布一个视图查看模型映射模板,我换用我的应用“对话框模板”一ContentControl中查看。 然后,您可以为您的DialogWindow尽可能多的“主模板”,只要你想(像一个“像精灵”,例如)。
直接法
当应用程序开始。如果我理解正确MainWindowView通过统一解决,从而解决其对MainWindowViewModel依赖?
如果这是您使用我建议继续在同一路径上,并让MainWindowView处理通过该按钮简单的单击处理新视图的开口的流动。 在此处理程序然后可以解决新的观点,这将解决该视图的视图模型,然后你回到MVVM土地,用于新视图中。
该解决方案是直线前进,并会完全正常工作对于大多数小型应用。
对于更复杂的应用程序更重的方法
如果你不希望那种观点,第一流的,我建议引入某种控制器/主持人,协调意见和观点的模型。 主讲人是负责有关是否/何时真正开启/关闭的意见等作出决定。
这是一个相当沉重的抽象,虽然,这是更适合更复杂的应用,所以一定要确保你真正得到足够的利益出它来证明增加抽象/复杂性。
以下是对这种方法可能看起来像一个代码示例:
public partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
var container = new UnityContainer();
container.RegisterType<IMainView, MainWindow>();
container.RegisterType<ISecondView, SecondWindow>();
container.RegisterType<IMainPresenter, MainPresenter>();
container.RegisterType<ISecondPresenter, SecondPresenter>();
var presenter = container.Resolve<IMainPresenter>();
presenter.ShowView();
}
}
public interface IMainPresenter
{
void ShowView();
void OpenSecondView();
}
public interface ISecondPresenter
{
void ShowView();
}
public interface ISecondView
{
void Show();
SecondViewModel ViewModel { get; set; }
}
public interface IMainView
{
void Show();
MainViewModel ViewModel { get; set; }
}
public class MainPresenter : IMainPresenter
{
private readonly IMainView _mainView;
private readonly ISecondPresenter _secondPresenter;
public MainPresenter(IMainView mainView, ISecondPresenter secondPresenter)
{
_mainView = mainView;
_secondPresenter = secondPresenter;
}
public void ShowView()
{
// Could be resolved through Unity just as well
_mainView.ViewModel = new MainViewModel(this);
_mainView.Show();
}
public void OpenSecondView()
{
_secondPresenter.ShowView();
}
}
public class SecondPresenter : ISecondPresenter
{
private readonly ISecondView _secondView;
public SecondPresenter(ISecondView secondView)
{
_secondView = secondView;
}
public void ShowView()
{
// Could be resolved through Unity just as well
_secondView.ViewModel = new SecondViewModel();
_secondView.Show();
}
}
public class MainViewModel
{
public MainViewModel(MainPresenter mainPresenter)
{
OpenSecondViewCommand = new DelegateCommand(mainPresenter.OpenSecondView);
}
public DelegateCommand OpenSecondViewCommand { get; set; }
}
public class SecondViewModel
{
}
<!-- MainWindow.xaml -->
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Command="{Binding OpenSecondViewCommand}" Content="Open second view" />
</Grid>
</Window>
<!-- SecondWindow.xaml -->
<Window x:Class="WpfApplication1.SecondWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SecondWindow" Height="350" Width="525">
<Grid>
<TextBlock>Second view</TextBlock>
</Grid>
</Window>
这篇文章提出了一个类似的解决方案是什么,我在生产中使用过。
要打开新的窗口MainWindowView
,你需要传递的参考Frame
部件或整个窗口MainWindowViewModel
对象但是(你可以绑定命令转换按钮或东西的时候做到这一点,他们通过为对象),也可以导航到新的页面,如果没有什么特殊的,你需要做的ViewModel
转换时,你可以使用经典的ButtonClick
事件或W / E在MainWindowView.cs
会为你做导航,这是确定的基本转变。
PS我不知道为什么你使用不同的项目的ViewModels /查看/模型。