Построение моделей представления на основе вложенных объектов моделей в шаблонах WPF и MVVM - PullRequest
12 голосов
/ 22 ноября 2010

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

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

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 ..

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

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

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

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

Ответы [ 4 ]

3 голосов
/ 22 ноября 2010

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

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

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

2 голосов
/ 30 ноября 2010

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

Решением было просто оставить модели такими, какими они были в начале, и прикрепить к коллекциям обработчик событий для 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;
        }
    }
}

Таким образом, я могу прикрепить новый Цвет / Стиль / Команду к моделям вида для поддержания чистоты моих базовых моделей

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

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

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

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

1 голос
/ 22 ноября 2010

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

Мой подход заключался вbuild - для вашего примера - PatternViewModel с ObservableCollection

.Это не противоречит MVVM, потому что представление привязано к коллекции.

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

0 голосов
/ 30 декабря 2010

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

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

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

...