Большинство приложений MVVM имеют такую архитектуру:
View -> ViewModel -> Model -> Repository
Я недавно поддерживал вариант:
View -> ViewModel <- Presenter -> Model -> Repository
(где A -> B означает «A знает о B», но B не знает об A.)
Обратите внимание, что в обоих случаях единственное, что известно о репозитории, - это модель, а не модель представления. Ваша модель - это не только доменные объекты, она также должна содержать бизнес-логику. Очевидно, одна из пользовательских историй, которую должна поддерживать ваша бизнес-логика, - это то, что я назову MemberEditTask
:
public class MemberEditTask
{
private readonly Member _member;
public MemberEditTask(Member member, IRepository repository)
{
this._member = member;
this.StatusChoices = repository.GetPossibleMemberStatuses(member);
}
public ReadOnlyCollection<MemberStatus> StatusChoices { get; private set; }
public MemberStatus Status
{
get { return this._member.Status; }
set
{
if(!this.StatusChoices.Contains(value))
{
throw new ArgumentOutOfRangeException();
}
this._member.Status = value;
}
}
}
Вся эта логика принадлежит вашей модели, поскольку список возможных вариантов (и подтверждение того, что один из них был фактически выбран) определяется бизнес-логикой. Вы также можете представить себе другую вещь, потребляющую MemberEditTask
, например, автоматизированный процесс, выполняющийся на сервере, который редактирует участника в ответ на файл, загруженный на FTP-сервер, или фоновый процесс (устанавливающий статус Неактивный после определенного количества времени). Все эти вещи должны выполнять одни и те же бизнес-правила, поэтому все они должны быть общими (не во ViewModel).
Итак, с учетом этого класса класс ViewModel выглядит следующим образом:
public class MemberEditViewModel : ViewModelBase
{
private readonly MemberEditTask _task;
public MemberEditViewModel(MemberEditTask task)
{
this._task = task;
}
public IEnumerable<MemberStatus> StatusChoices
{ get { return this._task.StatusChoices; }
public MemberStatus Status
{
get { return this._task.Status; }
set
{
this._task.Status = value;
NotifyAllPropertiesChanged();
}
}
}
В этом случае, для очень простого удобства, просто поверьте, что NotifyAllPropertiesChanged
- это защищенный метод ViewModelBase
, который использует отражение, чтобы вызвать событие PropertyChanged
для всех открытых свойств ViewModel. , :) Это, конечно, излишне, но это ведет к более важному моменту ...
Это почти глупый пример, потому что в этом случае MemberEditViewModel
не требуется. Если параметр View является единственной настройкой Status
, тогда на самом деле нет необходимости вызывать событие измененного свойства! Конечно, в реальном мире у вас будет больше свойств и будут взаимодействия. Причина существования ViewModel состоит в том, чтобы уведомлять потребителей об изменении его свойств, связанных с представлением, чего не делает Модель (и, по моему мнению, этого не должно). (ViewModel также имеет дополнительную специфичную для View логику для поддержки анимации и т. Д.)
Итак, вернемся к вашему вопросу ... является ли MemberRepository ответственным за выполнение получения статусов, не имеет значения с точки зрения ViewModel, потому что репозиторий является службой, используемой моделью. Модель - это сервис, используемый ViewModel. Сделайте свою Модель задачи / рабочего процесса / процесса / того, что выставляет список параметров состояния.
Извините, если это было многословно.