使用带棱镜的MVVM在视图之间切换 [英] Changing between views using MVVM with prism

查看:99
本文介绍了使用带棱镜的MVVM在视图之间切换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是WPF的新手,但据我所读,构建应用程序的正确方法是在同一窗口上切换视图. 我的意思是类似带有菜单和显示视图的工作区的框架".

I'm new to WPF, but from what I've read, a correct way to build applications is to switch up views on the same window. What I mean is something like a "frame" with a menu and a workspace where views are shown.

到目前为止,我一直在关注此问题,

So far I've been following this, http://jesseliberty.com/2011/01/06/windows-phone-from-scratch%E2%80%93mvvm-light-toolkit-soup-to-nuts-3/ but that is for WP7 and I can't use the NavigationService on a WPF app.

我可以说我想要的最简单的东西是,mainwindow.xaml上有一个显示按钮的视图,当我按下该按钮时,我希望在同一窗口中显示一个新视图(和旧视图).消失).

I could say that the simplest thing I want is, the mainwindow.xaml has a view on it that displays a button, when I press that button I want a new view to be displayed on the same window (and the old view to disappear).

实施类似方法的正确方法是什么?

What is the correct way of implementing something like that?

这是从使用mvvm-light开始的,但最终演变为棱镜.请参阅我最后的答案以获取更多详细信息.

This started by using mvvm-light, but eventually evolved to prism. See my last answer to further details.

推荐答案

这是一个很好的问题-当我开始使用MVVM时,我也遇到了类似的问题.我只使用MS的Prism/CAL库.

This is a great question - I had similar questions when I started using MVVM. I use just the Prism/CAL libraries from MS.

我相信您正在寻找的是CAL中一个地区的想法.从本质上讲,它是一个呈现事物的命名容器控件.基本上,您可以在顶级用户界面中命名区域,例如主窗口.您的应用程序可能只有少数几个:可能是页眉,页脚和主窗口区域. (无论如何,这就是我的做法.).然后,从后面的代码中,您可以通过区域管理器访问该区域,将其清除,然后放入ViewModel.将ViewModel映射到适当的View,然后将出现新的View.

I believe what you're looking for is the idea of a Region in CAL. It's basically a named container control that presents things. Basically, you name a region in a top-level UI piece, like your main window. Your app probably has a small number of these: maybe a header, footer, and main window regions. (That's how I've done it anyways.). Then from code behind you can access the region through a region manager, clear it, and drop in your ViewModel. The ViewModel gets mapped to it's appropriate View and voila the new View appears.

从编码的角度来看,我通常看到它像这样分解: 您有一种NavigationController,它具有清除区域并显示新的ViewModel-> View的方法或两种方法,还具有类似GoToPageX()的方法.这将抽象区域经理.然后,每个页面都有一个ViewModel,每个页面都有一个View.每个ViewModel都通过依赖注入引入了NavigationController(但是,如果您不使用DI,则可以创建新模型).然后在ViewModel上,它公开一个Command,该Command映射到该按钮并调用NavigationController.

From a coding standpoint, I've usually seen it broken up like this: You have some sort of a NavigationController that has a method or two from clearing the region and showing a new ViewModel->View and also has methods like GoToPageX(). This abstracts the region manager. Then you've got a ViewModel for each page and a View for each page. Each ViewModel takes in the NavigationController via dependency injection (but you can create new ones if you're not using DI). Then on the ViewModel, it exposes a Command which gets mapped to the button and calls the NavigationController.

在某些地方还必须将ViewModels与用于显示它们的Views一起注册.

Somewhere you've also got to register the ViewModels with the Views used to show them.

这是一个NavigationController的示例:

Here's an example of a NavigationController:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Unity;
using KSheets.CoreModule.Presenter;
using Zephyr.Core.Logging;
using KSheets.CoreSheets.Sheet;
using System.IO;

namespace KSheets.CoreModule.Switch
{
    public class Switchboard : ISwitchboard
    {
        private ILoggingService<ISwitchboard> m_Logger;
        private IRegionManager m_RegionManager;
        private IUnityContainer m_UnityContainer;

        public Switchboard(
            ILoggingService<ISwitchboard> loggingService,
            IRegionManager regionManager,
            IUnityContainer unityContainer
            )
        {
            if (loggingService == null) throw new ArgumentNullException("loggingService");
            if (regionManager == null) throw new ArgumentNullException("regionManager");
            if (unityContainer == null) throw new ArgumentNullException("unityContainer");

            m_RegionManager = regionManager;
            m_UnityContainer = unityContainer;
            m_Logger = loggingService;
        }

        public void GoHome()
        {
            m_Logger.Log("Going home");

            var worksheetEditor = m_UnityContainer.Resolve<IWorksheetEditor>();
            worksheetEditor.Initialize();
            LoadView(RegionNames.EditorRegion, worksheetEditor);

            var batchExporter = m_UnityContainer.Resolve<IExportBatchPresenter>();
            LoadView(RegionNames.ExporterRegion, batchExporter);
        }

        private void LoadView(string regionName, object newView)
        {
            var region = m_RegionManager.Regions[regionName]; 
            var oldViews = region.Views;
            foreach (var oldView in oldViews)
                region.Remove(oldView);
            region.Add(newView);
            region.Activate(newView);
        }
    }
}

这是通过编程向ViewModel注册视图的示例.许多人都在XAML中执行此操作,但是如果使用依赖项注入,您也可以在代码中使IMO更好地工作,因为可以在模块加载时同时注册视图和依赖项注入.

Here's an example of registering a View with a ViewModel programmatically. Many folks do this in XAML but you can also do it in code which IMO works better if you're using dependency injection as you can register your views and your dependency injection stuff all at the same time when your module loads.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

namespace Zephyr.WPF.Utils
{
    public static class ResourceUtils
    {
        public static void RegisterView<T, U>()
        {
            DataTemplate template = new DataTemplate();
            FrameworkElementFactory factory = new FrameworkElementFactory(typeof(U));
            template.DataType = typeof(T).FullName;
            template.VisualTree = factory;
            Application.Current.Resources.Add(new DataTemplateKey(typeof(T)), template);
        }
    }
}

        private void RegisterViews()
        {
            ResourceUtils.RegisterView<WorksheetDisplay, WorksheetDisplayView>();
            ResourceUtils.RegisterView<ProblemSelector, ProblemSelectorView>();
            ResourceUtils.RegisterView<WorksheetEditor, WorksheetEditorView>();
            ResourceUtils.RegisterView<ExportBatchPresenter, ExportBatchView>();
        }

一天结束时,您需要一小部分可识别UI的代码(或一个UI控件,用于侦听从非UI代码发送的消息,这些信息知道有关 small UI,例如区域名称),并允许您将ViewModel粘贴到位.但是,此代码通常是极小的代码,除了开箱即用的组件外,绝对不需要任何代码.当您实际上必须在WPF中首次实现MVVM时,可以采用很多方法.陡峭的学习曲线,可以启动并运行简单的应用程序.

At the end of the day, you need a small bit of code that is UI aware (or a UI control that listens to messages sent from non-UI code that knows a small bit about the UI like region names) and allows you to glue the ViewModel into place. However, this code is usually super minimal and definitely requires no code-behind except for out of box components. MVVM is kind of a lot to take in when you actually have to implement it in WPF the first time; a steep learning curve for getting a simple app up and running.

这篇关于使用带棱镜的MVVM在视图之间切换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆