Как написать "ViewModelBase" в MVVM (WPF)



Я довольно новичок в среде программирования WPF. Я пытаюсь написать программу, используя шаблон проектирования MVVM.



Я провел несколько исследований и прочитал несколько статей, связанных с этим, и много раз я сталкивался с этой вещью под названием


ViewModelBase




Я знаю, что это такое.. Но могу ли я знать конкретно С чего я должен начать , чтобы иметь возможность написать свою собственную ViewModelBase? Нравится... По-настоящему понимая, что происходит, не становясь слишком сложный. Спасибо:)

844   5  

5 ответов:

Ничего не стоит использовать фреймворки MVVM, если вы не знаете, что происходит внутри.

Итак, давайте шаг за шагом создадим свой собственный класс ViewModelBase.
  1. ViewModelBase-это класс, общий для всех ваших viewmodels. Давайте перенесем всю общую логику в этот класс.

  2. Ваши ViewModels должны реализовать INotifyPropertyChanged (вы понимаете, почему?)

    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    Атрибут [CallerMemberName] не требуется, но он позволит вам написать: OnPropertyChanged(); вместо OnPropertyChanged("SomeProperty");, таким образом, вы избежите Строковой константы в своем коде. Пример:

    public string FirstName
    {
        set
        {
            _firtName = value;
            OnPropertyChanged(); //instead of OnPropertyChanged("FirstName") or OnPropertyChanged(nameof(FirstName))
        }
        get{ return _firstName;}
    }
    
    Обратите внимание, что OnPropertyChanged(() => SomeProperty) больше не рекомендуется, так как у нас есть оператор nameof В C# 6.
  3. Это обычная практика реализации свойств, которые вызывают PropertyChanged следующим образом:

    public string FirstName
    {
        get { return _firstName; }
        set { SetProperty(ref _firstName, value); }
    }
    

    Давайте определим SetProperty в вашей viewmodelbase:

    protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer<T>.Default.Equals(storage, value))
            return false;
        storage = value;
        this.OnPropertyChanged(propertyName);
        return true;
    }
    

    Он просто запускает событие PropertyChanged, когда значение свойства изменяется и возвращает true. он не запускает событие, когда значение не имеет изменено и возвращает false. Основная идея заключается в том, что метод SetProperty является виртуальным, и вы можете расширить его в более конкретном классе, например, чтобы вызвать проверку или вызвать событие PropertyChanging.

Это довольно. Это все, что должна содержать ваша ViewModelBase на данном этапе. Остальное зависит от вашего проекта. Например, ваше приложение использует базовую навигацию по страницам, и вы написали свой собственный NavigationService для обработки навигации из ViewModel. Таким образом, вы можете добавить свойство NavigationSerivce в ваш класс ViewModelBase, так что вы будете иметь доступ к нему от всех ваших viewmodels, если вы хотите.

Чтобы получить больше возможности повторного использования и сохранить SRP, у меня есть класс под названием BindableBase, который в значительной степени является реализацией INotifyPropertyChanged, как мы сделали здесь. Я повторно использую этот класс в каждом решении WPF / UWP / Silverligt / WindowsPhone, потому что он универсален.

Затем я в каждом проекте создаю пользовательский класс ViewModelBase, производный от BindableBase:

public abstract ViewModelBase : BindableBase
{
    //project specific logic for all viewmodels. 
    //E.g in this project I want to use EventAggregator heavily:
    public virtual IEventAggregator () => ServiceLocator.GetInstance<IEventAggregator>()   
}

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

public abstract PageViewModelBase : ViewModelBase
{
    //for example all my pages has title:
    public string Title {get; private set;}
}

Я мог бы иметь другой класс для диалогов:

public abstract DialogViewModelBase : ViewModelBase
{
    private bool? _dialogResult;

    public event EventHandler Closing;

    public string Title {get; private set;}
    public ObservableCollection<DialogButton> DialogButtons { get; }

    public bool? DialogResult
    {
        get { return _dialogResult; }
        set { SetProperty(ref _dialogResult, value); }
    }

    public void Close()
    {
        Closing?.Invoke(this, EventArgs.Empty);
    }
}

У вас есть некоторый пакет nuget для реализации MVVM

  1. MVVM light
  2. MVVM Cross
  3. Призма

Для меня проще для новичка является MVVM light, потому что он предоставляет некоторый образец кода.

Поэтому лучше установить этот пакет nuget, посмотреть на сгенерированный код и вернуться к нам для получения дополнительных объяснений, если вам это нужно.

Мне нравится Эта BaseVewModel она дает хороший чистый стиль вашим моделям представления. Проверьте различные сравнения " до " и "после". Конечно, ничего не является обязательным - если вам не нравится функция, которую предоставляет BaseViewModel, не используйте ее. Или измените его, потому что у вас есть исходный код. В частности, обратите внимание, что есть три различных способа реализации свойств с уведомлением об изменении-выберите уровень сложности, который вы понимаете/чувствуете себя комфортно с.

В большинстве фреймворков MVVM базовые классы ViewModel на самом деле содержат очень мало кода - обычно это просто реализация INotifyPropertyChanged и некоторые вспомогательные функции.

Взгляните на исходный код классов ViewModelBase и ObservableObject MVVM Light. ObservableObject-это в основном реализация INotifyPropertyChanged, использующая лямбда-выражение вместо "волшебных строк" для имени свойства. ViewModelBase расширяет ObservableObject и является в основном это служебный метод для определения того, работаете ли вы внутри Visual Studio designer

Здесь есть хорошая дискуссия: https://codereview.stackexchange.com/q/13823 по этому вопросу. Использует хороший подход с использованием выражений, так что вы получаете безопасность типа при вызове уведомления об изменении свойства.

Comments

    Ничего не найдено.