WPF打开从视图模型一个新的视图(WPF Open a new View from the View

2019-07-04 09:15发布

这是我的第一个WPF-MVVM应用程序,这是我的结构:

  1. 我的一个项目app.xaml打开应用程序,并覆盖OnStartup解决的主窗口。 (我这样做,由于参考);
  2. 对于我的观点的一个项目;
  3. 我的ViewModels一个项目;
  4. 为我示范工程之一。

而且我去下面的问题:我在MainWindowView和我点击一个按钮来显示另一种观点。 我应该怎么做,从我打开这个另一种观点认为MainWindowViewModel而我View Project具有参考ViewModel Project ,我不能引用ViewModel ProjectView Project

顺便说一句,我使用Unitydependency injection

所以,你能帮助我吗?

Answer 1:

有几种方法了这一点。

您可以定义一个对话框/导航/窗口服务界面,在项目中的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尽可能多的“主模板”,只要你想(像一个“像精灵”,例如)。



Answer 2:

直接法

当应用程序开始。如果我理解正确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>

这篇文章提出了一个类似的解决方案是什么,我在生产中使用过。



Answer 3:

要打开新的窗口MainWindowView ,你需要传递的参考Frame部件或整个窗口MainWindowViewModel对象但是(你可以绑定命令转换按钮或东西的时候做到这一点,他们通过为对象),也可以导航到新的页面,如果没有什么特殊的,你需要做的ViewModel转换时,你可以使用经典的ButtonClick事件或W / E在MainWindowView.cs会为你做导航,这是确定的基本转变。

PS我不知道为什么你使用不同的项目的ViewModels /查看/模型。



文章来源: WPF Open a new View from the ViewModel
标签: c# wpf xaml mvvm