Какова модель для MVVM?

Я прочитал несколько статей, руководств и сообщений в блогах о шаблоне MVVM. Однако есть одна вещь, которую я не понимаю. Принимая три «слоя»:

  • Model
  • Вид
  • Просмотр модели

Насколько я понял MVVM, модель содержит «необработанные» данные, например. имя и адрес в случае класса Student . Модель представления предоставляет свойства представления, которые представляют данные модели.

Пример для свойства в модели представления

public string Name {
 get { return model.Name; }
 set { model.Name = value; }
}

Пример модели

private string name;

public string Name {
 get { return name; }
 set { name = value; }
}

Это может показаться немного глупым, но разве это не создает избыточность? Почему мне нужно сохранить имя в модели и в модели представления? Почему нельзя полностью обрабатывать имя модели просмотра?

6
Очень хорошо поставленный вопрос, кстати: ясный, краткий и содержит пример кода.
добавлено автор Equality In Tech, источник

5 ответы

На таком простом примере этот ответ будет да (он необоснованно избыточен). Но, предположительно, страница будет содержать больше, чем просто один объект модели. У вас может быть состояние страницы, а также несколько других объектов модели, которые необходимо отслеживать. Это делается в ViewModel.

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

У вас также может быть форма для редактирования объекта Student. Если вы намерены проверить эти изменения, вы не захотите напрямую редактировать объект «Студент» до тех пор, пока изменения не будут проверены. ViewModel может действовать как место временного хранения в таком случае.

Note on the above: It is not uncommon for validation to occur in the Model, but even then you will probably want the user to be able to enter invalid values while in the process of editing a form. For example, if your Model does not allow a zero-length value in a field, you still want to enable your user to delete the value, move to another field (say, for example, to copy it) then return to the field and finish editing (paste). If you are tied directly to the Model, then your validation logic may not handle this "in-between", "not-yet-finished" state as you'd like. For example, you might not want to accost your user with validation errors until they've finished and clicked 'Save'.

Вероятно, у вас также будут объекты Command в ViewModel для обработки щелчков кнопок и т.п. Это были бы объекты, специфичные для домена, которые были бы бесполезны в модели.

ViewModels также полезны, когда вам нужно отфильтровать или как-то временно «модифицировать» объекты модели, чтобы получить что-то полезное на экране. Например, вы можете отобразить список всех пользователей в системе вместе с списком из десяти лучших исполнителей из них в режиме реального времени (обновляется каждые 10 секунд). Или вы можете показать список отчетов и график, показывающий общую скорость использования и т. Д. Фильтрация, сортировка и настройка этих данных будут иметь место в ViewModel.

Модель, с другой стороны, как правило, настолько чиста, насколько это возможно. В идеале вы хотите POCOs , которые (как правило) моделируют именно то, что находится в вашем постоянном хранилище (база данных или что там у вас). Если ваше постоянное хранилище имеет поля FirstName и LastName, то ваша модель тоже. Только в вашей модели ViewModel вы бы объединили их для получения поля Name (либо «First Last», либо «Last, First» в зависимости от потребностей View).

Например:

namespace Model
{
    public class Student
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class Class
    {
        public string Name { get; set; }
        public float Score { get; set; }
    }
}

namespace ViewModel
{
    public class EditStudentRecordViewModel
    {
        private Model.Student _student;
        private IEnumerable _studentClasses;

        /* Bind your View to these fields: */
        public string FullName
        {
            return _student.LastName + ", " + _student.FirstName;
        }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public IEnumerable PassingClasses
        {
            get
            {
                return _studentClasses.Where( c => c.Score >= 78 );
            }
        }

        public IEnumerable FailingClasses
        {
            get
            {
                return _studentClasses.Where( c => c.Score < 78 );
            }
        }

        public void Save()
        {
            List l_validationErrors = new List();
            if ( string.IsNullOrEmpty( this.FirstName ) )
                l_validationErrors.Add( "First Name must not be empty." );
            if ( string.IsNullOrEmpty( this.LastName ) )
                l_validationErrors.Add( "Last Name must not be empty." );

            if ( l_validationErrors.Any() )
                return;

            _student.FirstName = this.FirstName;
            _student.LastName = this.LastName;
            Model.Utilities.SaveStudent( _student );
        }
    }
}
5
добавлено

Модель представляет собой графический объект, который содержит вашу бизнес-логику.

Вот где вы держите поведение (валидация, расчет и т. Д.).

ViewModel - это то, что моделирует пользовательский интерфейс и его взаимодействия.

Они различны и имеют разные причины для существующего - точка шаблона заключается в том, чтобы разделить логику отображения на VVM (View и ViewModel) и полностью разделить вашу бизнес-логику.

5
добавлено

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

Возьмем вашу модель, предположим, что она называется Person .

И затем вы создаете модель представления для Person под названием PersonViewModel , которая выглядит следующим образом:

public class PersonViewModel
{
    public Person Person { get; set; }
}

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

Теперь предположим, что у вас есть кнопка в представлении, которая используется для сохранения экземпляра Person . Чтобы обеспечить лучший пользовательский интерфейс (UX), вы хотите включить кнопку, только если ваша модель действительно изменилась. Таким образом, вы реализуете интерфейс INotifyPropertyChanged в классе Person :

public class Person : INotifyPropertyChanged
{
    ...

Теперь может вывести свойство HasUnsavedChanges из вашего Person , которое свойство Enabled на кнопке сохранения будет связываться с , но эта логика имеет ничего , чтобы сделать с человеком.

Это место, в которое входит модель представления. Вы должны определить это свойство свойства представления в модели представления, например:

public class PersonViewModel
{
    public Person Person { get; set; }

    public bool HasUnsavedChanges { get; set; }
}

Затем ваша модель просмотра будет подписана на PropertyChanged интерфейса INotifyPropertyChanged и переключить свойство HasUnsavedChanges в модели представления.

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

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

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

4
добавлено

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

Просмотреть модели, с другой стороны, являются моими фактическими классами приложений, которые в конечном итоге используют «строительные блоки» (Модели) при создании и запуске приложения. Они выполняют такие функции, как выполнение расширенной проверки, обработки команд, обработки событий, любой бизнес-логики и т. Д.

Следует отметить, что вы не имеете , чтобы показывать свойства вашей модели в своей модели ViewModel, как в вашем примере кода. Это подход «Пурист MVVM», поскольку он полностью отделяет ваш слой модели от слоя «Вид», однако также вполне приемлемо подвергать всю модель представлению. Это то, что я обычно использую в большинстве небольших проектов из-за его простоты и отсутствия дублирования кода.

public MyModel CurrentModel
{
    get { return _model; }
    set 
    {
        if (_model != value)
        {
            _model = value;
            RaisePropertyChanged("CurrentModel");
        }
    }
}

Однако, если есть случаи, когда в представлении требуется только несколько свойств из Модели, или если проект достаточно велик, и я хочу, чтобы слои полностью разделялись, я показываю свойства модели для представления через ViewModel как у вас в вашем примере кода.

1
добавлено

Модель в MVVM точно такая же, как в MVP или Model2 MVC. Это одна из частей шаблонов, вдохновленных MVC, на которые не влияют вариации темы.

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

Model is not any single instance. Anyone who tels you otherwise is full of it.

Конкретные usecases, для которых MVVM был спроектирован, - это ситуация, когда вы не можете изменить ни модельный, ни визуальный экземпляры, или и то, и другое.

P.S. Хотя, если вы используете экземпляры ViewModel в соответствии с документацией ASP.NET MVC, то вы фактически НЕ используете MVVM. Это просто Model2 MVC с разными именами для вещей (где «viewmodels» - это фактически виды и «представления» - это шаблоны). Они вроде бы перепутались, когда они продавали Rails-подобную архитектуру как «MVC».

0
добавлено
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot