MVVM - Модель против ViewModel - где разместить мой код? - PullRequest
3 голосов
/ 19 июня 2019

Я создаю небольшое приложение для управления гоночными онлайн-лигами. Для этого у меня будет база данных, которая получает доступ к данным из Интернета и предоставляет доступ к объектам данных через интерфейс. База данных еще не существует, но я создал макет, который использует локальные файлы XML в качестве источника данных.

Небольшой пример для интерфейса лиги:

public interfac ISchedule
{
    string Name { get; set; }
    List<IRaceSession> Races { get; }
    // and some more properties …

    IRaceSession AddRace();
    void RemoveRace(IRaceSession race);
    // and some more Methods …
}

public interface IRaceSession
{
    uint RaceId { get; }
    DateTime Date { get; set; }
    TimeSpan Duration { get; set; }
    // and some more properties …
}

Теперь, чтобы получить это в моем шаблоне WPF с MVVM, я создал Модель для каждого объекта, который выставляет база данных, и внедрил там INPC. * Примечание: ContainerModel<> и ObservableModelCollection<> - это классы, которые я создал для обработки обновлений из базы данных, сохраняя при этом INPC без изменений.

public class ContainerModel<T>
{
    T Source { get; set; }

    public ContainerModel(T source)
    {
        Source = source;
    }

    void UpdateSource(T source)
    {
        // handle updates …
    }
}

public class ScheduleModel : ISchedule, ContainerModel<ISchedule>
{
    public string Name { get => Source.Name ; set { Source.Name = value; NotifyPropertyChanged(); } }

    public ObservableModelCollection<RaceSessionModel, IRaceSession> Races { get; }
    List<IRaceSession> ISchedule.Races => Source.Races

    public ScheduleModel(ISchedule source) : base(source)
    {
        Races = new ObservableModelCollection<RaceSessionModel, IRaceSession>(Source.Races);
    }

    IRaceSession AddRace()
    {
        Races.Add(// new Race Object);
    }
    void RemoveRace(IRaceSession race)
    {
        Races.Remove(// select race object to remove);
    }
}

public class RaceSessionModel : IRaceSession, ContainerModel<IRaceSession>
{
    public uint RaceId => Source.RaceId;
    puglic DateTime Date { get => Source.Date; set { Source.Date = value; NotifyPropertyChanged(); } }
    TimeSpan Duration { get => Source.Duration; set { Source.Duration = value; NotifyPropertyChanged(); } }


    //--> here come some more logic im not sure About:
    TimeSpan DurationHours 
    { 
        get => Duration.Hours;
        set 
        {
            // set only Hours componennt of Duration
            Duration = Duration
                .Subtract(Duration.Hours)
                .Add(value);
            NotifyPropertyChanged();
        }

    TimeSpan DurationMinutes 
    { 
        get => Duration.Minutes;
        set 
        {
            // set only Minutes componennt of Duration
            Duration = Duration
                .Subtract(Duration.Minutes)
                .Add(value);
            NotifyPropertyChanged();
        }
}

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

public class SchedulerViewModel : ViewModelBase //<-- just a Basic implementation of INPC
{
    private ScheduleModel _schedule;
    public ScheduleModel Schedule { get => _schedule; set { _schedule = value; NotifyPropertyChanged(); } }

    public SchedulerViewModel(ScheduleModel schedule)
    {
        Schedule = schedule;
    }

    // Commands and other properties communicating with the view
    // …
}

Теперь с этим дизайном у меня возникло несколько проблем. Я все еще нахожусь в процессе обдумывания всего шаблона проектирования, и я впервые создаю его с нуля.

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

  2. Как вы видите, мои модели также содержат некоторые виды вычислений для свойства Input. Должна ли эта «бизнес-логика» быть вне модели? Или это также было бы лучше поместить в ViewModel?

В конце концов, я сомневаюсь, что я представляю "модели" вообще. Было бы правильно называть их ViewModels, а затем действовать с Объектом из базы данных в качестве модели?

* Edit: Когда я начал с этого, я прочитал, что для каждого View вы должны указывать только один ViewModel, поэтому я создал свои классы вот так. Но я больше не уверен, правильно ли это.

Ответы [ 3 ]

1 голос
/ 19 июня 2019

Для передачи данных из модели в ViewModel я бы создал простые объекты (Dto - DataTransferObject) без (или очень минимальной) логики. Хорошее практическое правило заключается в том, что вы хотите, чтобы несохраненные данные в ViewModel сохранялись, а сохраненные данные - или данные, которые собираются сохранить - принадлежат модели.

//--> here come some more logic im not sure About:
TimeSpan DurationHours 
{ 
    get => Duration.Hours;
    set 
    {
        // set only Hours componennt of Duration
        Duration = Duration
            .Subtract(Duration.Hours)
            .Add(value);
        NotifyPropertyChanged();
    }

TimeSpan DurationMinutes 
{ 
    get => Duration.Minutes;
    set 
    {
        // set only Minutes componennt of Duration
        Duration = Duration
            .Subtract(Duration.Minutes)
            .Add(value);
        NotifyPropertyChanged();
    }

Я бы положил их в ViewModel. В модели, которую вы хотите, чтобы весь объект Timespan, только ViewModel должен знать об ограничениях, которые вы можете установить их отдельно в представлении.

Когда я начал с этого, я прочитал, что для каждого просмотра вы должны предоставить только одна ViewModel, поэтому я создал свои классы, как это. Но я больше не уверен, правильно ли это.

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

1 голос
/ 19 июня 2019

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

  • Модель по расписанию
  • Модель для RaceSession
  • ViewModel для RaceSession, содержащий модель RaceSession
  • ViewModel для расписания, содержащего модель расписания, коллекцию RaceSessionViewModels

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

Причина, по которой у меня не было бы коллекции моделей RaceSession в модели расписания, заключается в том, что если бы вы выполняли какие-либо манипуляции с приложениями для RaceSessions, это то, что принадлежит ViewModel, поэтому вы ' Затем я смотрю на модель расписания с коллекцией RaceSessionViewModels. Поэтому я бы строго придерживался моделей как отдельных объектов данных, без каких-либо встроенных отношений сущностей (объединений) - такого рода отношений я бы встроил в слой ViewModel. Даже если вам не нужен ViewModel для RaceSession, у меня все равно будет коллекция моделей RaceSession в Schedule ViewModel.

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

Что касается вычислений TimeSpan, я бы, вероятно, использовал часы и минуты как get только свойства (в RaceSession ViewModel), с другими методами в RaceSessionViewModel, которые напрямую изменяют свойство Duration. Точная реализация этого будет зависеть от того, действительно ли вы меняли их в базе данных при обновлении.

Некоторые примеры псевдокодов

public class RaceSession : INPC
{
    INPCProperties

    RaceSession(inpcProperties)
    {
        INPCProperties = inpcProperties;
    }
}

public class RaceSessionViewModel : INPC
{
    public RaceSession RaceSession { get; set (INPC); }

    public int Hours => RaceSession.Duration.Hours;

    public RaceSessionViewModel(raceSession)
    {
        RaceSession = raceSession;
    }

    private void SetDurationHours(int hours)
    {
        RaceSession.Duration =
            Duration
            .Subtract(Duration.Hours)
            .Add(hours);

        NotifyPropertyChanged("Hours");
    }
}
0 голосов
/ 19 июня 2019
  1. Нет.Модель представления связывает данные (модели, а не базу данных) с представлением.Но он не манипулирует ни представлением, ни базой данных.
  2. Я бы не оставил это в моделях.Такого рода вещи на самом деле принадлежат модели представления.В каждом представлении вы можете представить несколько представлений, но вам определенно нужен по крайней мере один для начала.Я предлагаю, так как вы уже начали создавать свой MVVM, вы теперь где-то в Интернете ищите пример, который реализует этот шаблон проектирования.Я полагаю, вы уже читали некоторые теории, стоящие за этим.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...