Подтвердить что ты не робот

Создание ViewModels на основе вложенных объектов модели в WPF и шаблоне MVVM

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

(я упростил модели, чтобы быть более четкими)

public class Hit
{
   public bool On { get; set;}
   public Track Track { get; set; }
}
public class Track
{
   public ObservableCollection<Hit> Hits { get; set; }
   public LinearGradientBrush Color { get; set; }
   public Pattern Pattern { get; set; }
}
public class Pattern
{
   public string Name { get; set; }
   public ObservableCollection<Tracks> Tracks { get; set; }
}

Теперь, моя проблема в том, как создать ViewModels..

Мне нужно сохранить исходные отношения через модели, beacaus У меня есть метод Serialize() на шаблоне, который сериализует его в XML файл.. (с соответствующими треками и хитами)

Чтобы иметь возможность привязывать шаблон к пользовательским элементам управления, и вложенные шаблоны, я должен также иметь шаблон PatternViewModel с ObservableCollection <TrackViewModel> в нем, то же самое для TrackViewModel и HitViewModel.. и я neet для создания пользовательских свойств представления на моделях представления, которые не являются частью бизнес-объекта (цвета и т.д.).

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

у кого есть лучший подход/решение?

4b9b3361

Ответ 1

В итоге я использовал часть решения, предложенное Джо Уайтом, слегка отличающимся образом

Решение заключалось в том, чтобы просто оставить модели такими, какими они были в начале, и привязать к коллекциям обработчик событий для CollectionChanged из внутренних коллекций, например, PatternViewModel будет выглядеть следующим образом:

public class PatternViewModel : ISerializable
{
    public Pattern Pattern { get; set; }
    public ObservableCollection<TrackViewModel> Tracks { get; set; }

    public PatternViewModel(string name)
    {
        Pattern = new Pattern(name);
        Tracks = new ObservableCollection<TrackViewModel>();
        Pattern.Tracks.CollectionChanged += new NotifyCollectionChangedEventHandler(Tracks_CollectionChanged);
    }

    void Tracks_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach (Track track in e.NewItems)
                {
                    var position = Pattern.Tracks.IndexOf((Track) e.NewItems[0]);
                    Tracks.Insert(position,new TrackViewModel(track, this));
                }
                break;
            case NotifyCollectionChangedAction.Remove:
                foreach (Track track in e.OldItems)
                    Tracks.Remove(Tracks.First(t => t.Track == track));
                break;
            case NotifyCollectionChangedAction.Move:
                for (int k = 0; k < e.NewItems.Count; k++)
                {
                    var oldPosition = Tracks.IndexOf(Tracks.First(t => t.Track == e.OldItems[k]));
                    var newPosition = Pattern.Tracks.IndexOf((Track) e.NewItems[k]);
                    Tracks.Move(oldPosition, newPosition);
                }
                break;
        }
    }
}

Итак, я могу прикрепить новую команду Color/Style/Command на моделях просмотра, чтобы мои базовые модели были чистыми

И всякий раз, когда я добавляю/удаляю/перемещаю элементы в коллекции базовых моделей, коллекции моделей представлений остаются в синхронизации друг с другом

К счастью, мне не нужно управлять множеством объектов в моем приложении, поэтому дублированные данные и производительность не будут проблемой

Мне не нравится это слишком много, но он работает хорошо, и это не очень много работы, просто обработчик событий для модели представления, содержащий другие, рассматривающий коллекции моделей (в моем случае один для PatternViewModel для синхронизации TrackViewModels, а другой - в TrackViewModel для управления HitViewModels)

Все еще интересуются вашими идеями или лучшими идеями =)

Ответ 2

Одна вещь, которую я сделал с некоторым успехом, - это перемещение ObservableCollection из модели. Вот моя общая схема:

  • В объектах модели выведите свойство типа IEnumerable<TModel>, которое дает доступ к коллекции только для чтения. Используйте обычный старый List<TModel>, а не ObservableCollection, как коллекцию поддержки.
  • Для кода, который необходимо изменить коллекции моделей (добавить, удалить и т.д.), добавить методы к объекту модели. У вас нет внешнего кода, непосредственно управляющего коллекцией; инкапсулировать, что внутри методов на модели.
  • Добавить события в модель для каждого типа изменений, которые вы разрешаете. Например, если ваша модель поддерживает только добавление элементов в конец коллекции и удаление элементов, вам потребуется событие ItemAdded и событие ItemDeleted. Создайте потомку EventArgs, который дает информацию об элементе, который был добавлен. Огоньте эти события из методов мутации.
  • В вашей модели ViewModel укажите ObservableCollection<TNestedViewModel>.
  • Примените ViewModel к событиям на модели. Всякий раз, когда модель говорит, что элемент был добавлен, создайте экземпляр ViewModel и добавьте его в ViewModel ObservableCollection. Всякий раз, когда модель говорит, что элемент был удален, повторите команду ObservableCollection, найдите соответствующую ViewModel и удалите ее.
  • Помимо обработчиков событий, убедитесь, что весь код мутации коллекции выполняется с помощью модели - рассматривайте ViewModel ObservableCollection как строго что-то для потребления вида, а не то, что вы используете в коде.

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

Ответ 3

Я думаю, что у меня была такая же проблема, и если вы сделаете это как "PatternViewModel с ObservableCollection <TrackViewModel> ", вы также получите огромное влияние на вашу производительность, потому что вы начинаете дублировать данные.

Мой подход заключался в том, чтобы построить - для вашего примера - шаблон PatternViewModel с ObservableCollection <Track> . Это не противоречит MVVM, потому что представление привязано к коллекции.

Таким образом, вы можете избежать дублирования отношений.

Ответ 4

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

Итак, в вашем случае вы можете привязать Tracks непосредственно к (в качестве примера) списку с конвертером, который создает новый TrackViewModel из трека. Все, что ваш контроль когда-либо видел, - это объект TrackViewModel, и все ваши модели когда-либо будут видеть другие модели.

Я не уверен в динамическом обновлении этой идеи, хотя я еще не пробовал ее.