Переключение между представлениями с использованием MVVM с призмой - PullRequest
5 голосов
/ 24 апреля 2011

Я новичок в WPF, но из того, что я прочитал, правильный способ создания приложений - переключать представления в одном и том же окне.Я имею в виду что-то вроде «рамки» с меню и рабочим пространством, где отображаются представления.

До сих пор я следил за этим, http://jesseliberty.com/2011/01/06/windows-phone-from-scratch%E2%80%93mvvm-light-toolkit-soup-to-nuts-3/, но это для WP7, и я могуне используйте NavigationService в приложении WPF.

Я могу сказать, что самое простое, что мне нужно, это mainwindow.xaml, который отображает кнопку, и когда я нажимаю эту кнопку, я хочу новуюпредставление, которое будет отображаться в том же окне (и старое представление исчезнет).

Как правильно реализовать нечто подобное?

РЕДАКТИРОВАТЬ: Это началось с использованием mvvm-light,но в итоге превратился в призму.Смотрите мой последний ответ для более подробной информации.

Ответы [ 2 ]

2 голосов
/ 24 апреля 2011

Это отличный вопрос - у меня были похожие вопросы, когда я начал использовать MVVM.Я использую только библиотеки Prism / CAL от MS.

Я считаю, что вам нужна идея Region в CAL.Это в основном именованный контейнерный элемент управления, который представляет вещи.По сути, вы называете регион в пользовательском интерфейсе верхнего уровня, например, в главном окне.Ваше приложение, вероятно, имеет небольшое количество из них: возможно, верхний и нижний колонтитулы и области основного окна.(Вот как я это сделал в любом случае.)Затем из кода вы можете получить доступ к региону через менеджера региона, очистить его и вставить в свою ViewModel.ViewModel сопоставляется с соответствующим View, и вуаля появляется новый View.

С точки зрения кодирования, я обычно видел, как он разбивается следующим образом: у вас есть своего рода NavigationController, у которого есть метод или дваот очистки региона и отображения нового ViewModel-> View, а также имеет методы, такие как GoToPageX ().Это реферат регионального менеджера.Тогда у вас есть ViewModel для каждой страницы и View для каждой страницы.Каждый ViewModel принимает NavigationController через внедрение зависимостей (но вы можете создавать новые, если вы не используете DI).Затем в ViewModel он предоставляет Команду, которая отображается на кнопку и вызывает NavigationController.

Где-то вы также должны зарегистрировать ViewModels с помощью представлений, используемых для их отображения.

Вот пример 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);
        }
    }
}

Вот пример регистрации View с помощью ViewModel программно.Многие люди делают это в XAML, но вы также можете делать это в коде, который работает в IMO лучше, если вы используете внедрение зависимостей, так как вы можете регистрировать свои представления и все свои элементы внедрения зависимостей одновременно при загрузке модуля.

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>();
        }

В конце дня вам понадобится небольшой кусочек кода, который осведомлен о пользовательском интерфейсе (или элемент управления пользовательского интерфейса, который прослушивает сообщения, отправленные из не-пользовательского кода, который знает маленький бит опользовательский интерфейс любит имена регионов) и позволяет вам приклеить ViewModel на место.Тем не менее, этот код обычно очень минималистичен и определенно не требует никакого кода, кроме готовых компонентов.MVVM - это что-то особенное, когда вам действительно нужно впервые реализовать его в WPF;крутая кривая обучения для запуска и запуска простого приложения.

1 голос
/ 05 мая 2011

Я пришел сюда, чтобы дополнить ответ J-Trana .

Он действительно заинтересовал меня Призмой, и я рад, что он сделал.Это просто потрясающе.Я провел последние несколько недель, читая об этом, просматривая документы и краткие примеры, которые идут с этим.Это были мои основные рекомендации.

Итак, о решении ...

Prism Regions действительно было то, что я хотел.Предоставленный им Switchboard был ключевым в моей реализации, но я немного его подправил.

Сначала я пропустил внутри него UnityContainer, чтобы я мог получить больше гибкости.(Или я думаю, что это дает мне.) Во-вторых, я создал метод LoadModule (потому что у меня есть модульная структура), как это.

public void LoadModule(string module) { 
            IModuleManager moduleManager = m_UnityContainer.Resolve(); 

            moduleManager.LoadModule(module); 
}

Из того, что я получил, когда этот LoadModule выполняет Initialize() метод моих модулей, которые выглядят примерно так ...

public void Initialize()
    {

        Switchboard switchboard = Switchboard.GetSwitchboard();

        IUnityContainer container = switchboard.GetCatalog();

        switchboard.LoadView(RegionNames.ShellMainRegion, container.Resolve<HelloWorldView>());

    }

И это работает!

Несколько советов, заслуживающих внимания: - `// Свойство, предоставляющее контекст(ViewModel) для представления.

    [Dependency]
    public HelloWorldViewModel HelloWorldViewModel
    {
        set
        {
            this.DataContext = value;
        }
    }
  • Это соединяет ViewModel с представлением как свойство кода кода позади.
  • this.Container.RegisterType ();
  • Я регистрирую свои модули следующим образом:

`Тип HelloWorldType = typeof (HelloWorldModule);
this.ModuleCatalog.AddModule (new ModuleInfo ()

        {

            ModuleName = ModuleNames.HelloWorldModule,

            ModuleType = HelloWorldType.AssemblyQualifiedName,

            InitializationMode = InitializationMode.OnDemand

        }); `

- И мой коммутатор находится на моём модуле инфраструктуры. Создание View переходит к модулю, в котором он есть, и это решило мою проблему.

Надеюсь, это не слишком запутанно, и я бы действительнокак некоторые комментарии о том, как я делаю эти вещи ... Я делаю это "правильно" вау?Есть ли более элегантный способ?Вещи, как это ...

В любом случае, я надеюсь, что это помогает и мотивирует людей, которые пытаются изучать призму.

PS: Как работает этот кодовый тег?И могу ли я изменить теги?mvvm-light больше не имеет смысла.

...