Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/302.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF从ViewModel打开一个新视图_C#_Wpf_Xaml_Mvvm - Fatal编程技术网

C# WPF从ViewModel打开一个新视图

C# WPF从ViewModel打开一个新视图,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,这是我的第一个WPF-MVVM应用程序,这是我的结构: 使用myapp.xaml打开应用程序并覆盖启动时的以解析主窗口的一个项目。(我这样做是因为参考) 我的观点是一个项目 一个用于我的ViewModels的项目 我的模型有一个项目 我有以下问题:我在MainWindowView上,点击一个按钮显示另一个视图。如果我的视图项目引用了视图模型项目,而我不能引用视图项目,我该如何从我的主窗口视图模型打开另一个视图呢 顺便说一下,我正在使用Unity进行依赖项注入 所以,您能帮我吗?要从MainWin

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

  • 使用my
    app.xaml
    打开应用程序并覆盖启动时的
    以解析主窗口的一个项目。(我这样做是因为参考)
    
  • 我的观点是一个项目
  • 一个用于我的ViewModels的项目
  • 我的模型有一个项目
  • 我有以下问题:我在
    MainWindowView
    上,点击一个按钮显示另一个视图。如果我的
    视图项目
    引用了
    视图模型项目
    ,而我不能引用
    视图项目
    ,我该如何从我的
    主窗口视图模型
    打开另一个视图呢

    顺便说一下,我正在使用
    Unity
    进行
    依赖项注入


    所以,您能帮我吗?

    要从
    MainWindowView
    打开新窗口,您需要将
    框架
    组件或整个窗口的引用传递到
    MainWindowViewModel
    对象(您可以在将命令绑定到转换按钮或其他东西时执行此操作,将它们作为对象传递),但是,您可以在那里导航到新页面,如果转换时在
    ViewModel
    中没有什么特别的事情需要做,您可以使用经典的
    按钮单击
    事件或
    MainWindowView.cs
    中的w/e来为您导航,这对于基本转换来说是可以的


    另外,我不知道为什么您对视图模型/视图/模型使用不同的项目。

    有几种方法

    您可以定义在ViewModels项目中定义的对话框/导航/窗口服务界面。您需要决定ViewModels将如何表示要打开的窗口。我通常使用IDialogViewModel接口(我的一些ViewModels实现了该接口),并将ViewModel的一个实例传递给服务,但您可以使用枚举、字符串,无论您想要什么,这样您的实现就可以映射到将要打开的实际窗口

    例如:

    public interface IDialogService
    {
        bool? ShowDialog(object dialogViewModel); 
    }
    
    想要打开新窗口的ViewModels将收到该服务的一个实例,并使用它来表示打开窗口的意图。在Views项目中,您将定义一个实现服务接口的类型,并使用打开窗口背后的实际逻辑

    举个例子:

    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;
        }
    
    }
    
    公共类DialogService:IDialogService
    {
    私有堆栈windowStack=新堆栈();
    公共对话服务(窗口根目录)
    {
    此.windowStack.Push(根);
    }
    public bool?ShowDialog(对象对话框ViewModel)
    {
    窗口对话框=映射窗口(dialogViewModel);
    dialog.DataContext=dialogViewModel;
    dialog.Owner=this.windowStack.Peek();
    此.windowStack.Push(对话框);
    布尔结果;
    尝试
    {
    结果=dialog.ShowDialog();
    }
    最后
    {
    this.windowStack.Pop();
    }
    返回结果;
    }
    }
    
    您的主项目将负责在需要对话服务的ViewModels中创建和注入对话服务。在本例中,应用程序将创建一个新的对话服务实例,并将主窗口传递给它

    类似的方法是使用某种形式的消息传递模式()。 此外,如果您想要一些简单的东西,还可以让ViewModels在打开窗口时引发事件,并让视图订阅这些事件

    编辑

    我在应用程序中使用的完整解决方案通常有点复杂,但基本上就是这样。我有一个基本的DialogWindow,它需要一个ViewModel,作为DataContext实现IDialogViewModel接口。此界面抽象了您在对话框中期望的一些功能,如接受/取消命令以及关闭的事件,以便您也可以从ViewModel关闭窗口。DialogWindow基本上由ContentPresenter组成,ContentPresenter的内容属性绑定到DataContext,并在DataContext发生更改(以及其他一些事情)时钩住close事件

    每个“对话框”包含一个IDialogViewModel和一个关联的视图(UserControl)。为了映射它们,我只在应用程序的资源中声明隐式数据模板。在我展示的代码中,唯一的区别是没有方法MapWindow,窗口实例始终是DialogWindow

    我使用另外一个技巧在对话框之间重用布局元素。方法是将它们包括在对话框窗口中(接受/取消按钮等)。我喜欢保持对话框窗口干净(这样我就可以使用它来创建“非对话框”对话框)。我使用公共接口元素为ContentControl声明一个模板,当我声明一个视图ViewModel映射模板时,我使用一个应用了“对话框模板”的ContentControl包装视图。然后,您可以为您的对话框窗口设置任意数量的“主模板”(例如,像“向导式”模板)。

    直接方法 如果我理解正确,当应用程序启动时,MainWindowView是通过Unity解决的,这解决了它对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>