Страницы

Поиск по вопросам

суббота, 13 июля 2019 г.

Переключение страниц в wpf по архитектуре mvvm

Всем доброго времени суток. Моя проблема заключается в следующем, как реализовать в WPF переключение между страницами используя MVVM. Переключение должно осуществлять по нажатию кнопки, расположенных слева на изображении.Страниц будет всего лишь шесть, как и кнопок.


Ответ

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

с рефлексией, все дела, как у четких пацанов...:) Это не мой мопед, я чисто его сп... подсмотрел в проекте NAudio. Подход довольно интересный, кстати.
Создаем вот такой интерфейс
public interface IModule { ///

/// Название выводимое в меню /// string Name { get; } /// /// Ссылка на вьюшку /// UserControl UserInterface { get; } /// /// Отключение текущей вьюшки, для вьюмоделей с реализацией IDisposable /// void Deactivate(); }
Далее для каждой пары View & ViewModel создается еще один класс, который реализует этот интерфейс таким образом:
class SeparateDemo : IModule { //наша неразлучная парочка private SeparateDemoView view; private SeparateDemoViewModel viewModel;
public string Name => "Вьюшка SeparateDemo";
public UserControl UserInterface { get { if (view == null) CreateView(); return view; } }
private void CreateView() { //загружаем вьюшку view = new SeparateDemoView(); //её вьюмодель viewModel = new SeparateDemoViewModel(); //связываем их между собой view.DataContext = viewModel; }
public void Deactivate() { viewModel.Dispose(); view = null; } }
т.е. это такой загрузчик для пары View & ViewModel. Далее это у нас MainWindow.xaml

Это её вьюмодель, которая подгружает и отображает нужную вьюшку
class MainWindowViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged = delegate { };
//ctor public MainWindowViewModel(IEnumerable modules) { Modules = modules.OrderBy(m => m.Name).ToList(); if (this.Modules.Count > 0) { SelectedModule = this.Modules[0]; } }
//Properties
/// /// Список всех возможных загрузчиков пар View и ViewModel /// public List Modules { get; private set; }
/// /// Выбранная и загруженная парочка View и ViewModel /// private IModule _SelectedModule; public IModule SelectedModule { get { return _SelectedModule; } set { if (value == _SelectedModule) return; if (_SelectedModule != null) _SelectedModule.Deactivate(); _SelectedModule = value; PropertyChanged(this, new PropertyChangedEventArgs(nameof(SelectedModule))); PropertyChanged(this, new PropertyChangedEventArgs("UserInterface")); } }
/// /// То, что отображает View через ContentPresenter /// public UserControl UserInterface { get { if (SelectedModule == null) return null; return SelectedModule.UserInterface; } } }
А вот теперь самая мякотка - тут без рефлексии не обойтись
static class ReflectionHelper { public static IEnumerable CreateAllInstancesOf() { return typeof(ReflectionHelper).Assembly.GetTypes() .Where(t => typeof(T).IsAssignableFrom(t)) .Where(t => !t.IsAbstract && t.IsClass) .Select(t => (T)Activator.CreateInstance(t)); } }
Подправляем App.xaml такой строчкой - Startup="Application_Startup"> И тогда App.xaml.cs такой
public partial class App : Application { private void Application_Startup(object sender, StartupEventArgs e) { var mainWindow = new MainWindow();
var modules = ReflectionHelper.CreateAllInstancesOf();
var vm = new MainWindowViewModel(modules); mainWindow.DataContext = vm; mainWindow.Closing += (s, args) => vm.SelectedModule.Deactivate(); mainWindow.Show(); } }
Вот и все. Как вариант можно сделать промежуточный класс abstract class ModuleBase : IModule и тогда загрузчик пары можно сделать таким
class FirstDemo : ModuleBase { public override string Name { get { return "Вьюшка FirstDemo"; } }
protected override UserControl CreateViewAndViewModel() { return new FirstDemoView() { DataContext = new FirstDemoViewModel() }; } }
Весь проект целиком можно скачать здесь

Комментариев нет:

Отправить комментарий