2010-07-10 3 views
0

У меня есть эти ViewModels: RecordViewModel, ComponentViewModel, где RecordViewModel по существу является контейнером для нескольких ComponentViewModels.WPF: одобрение ViewModel?

Дисплей этих ViewModels в настоящее время обрабатываемых DataTemplates, которые выглядят примерно так:

<DataTemplate DataType="{x:Type vm:RecordViewModel}" > 
    <ItemsControl ItemsSource={Binding Components} /> 
</DataTemplate> 

<DataTemplate DataType="{x:Type vm:ComponentViewModel}" > 
    <TextBox Text={Binding Name} /> 
</DataTemplate> 

То, что я хотел, чтобы обеспечить в настоящее время является способ, чтобы изменить порядок отображения на ComponentViewModels и удалить определенную ComponentViewModel из списка. Я начал делать это, манипулируя DataTemplate компонента ComponentViewModel и добавляя кнопки, которые предоставляют эти функции (щелчок затем запускает метод в ComponentViewModel, который (посредством ссылки «Родительский» к RecordViewModel) вызывает метод в RecordViewModel для выполните операцию (например, component.Parent.DeleteComponent (this)).

Проблема с этим в моей работе заключается в том, что на самом деле это запись, которая должна манипулировать позицией компонентов/удалять компонент, а не сам компонент.

Итак, я подумал об использовании adorner, который прикрепляется к RecordViewModel, и отображает кнопки для обеспечения функциональности (удаление, перемещение вверх, перемещение вниз) для каждой из ComponentViewModels.

Проблема заключается в том, что эти знаменатели должны ссылаться на элемент управления, который они украшают (что было нормально, я просто привязывался к ItemsControl в Record-DataTemplate), однако проблема возникает, когда я хочу показать кнопки в правильном положении для каждого компонента ComponentViewModel. У меня есть только ссылка на данные ComponentViewModels, а не на их визуальное представление (вещь, определенная в DataTemplate), поэтому я не знаю, где разместить 3 кнопки.

Есть ли способ обойти это? Или возможно, что для этих требований использование ViewModels/DataTemplates просто не очень хорошая идея, и поэтому я должен использовать Control-производные/ControlTemplates?

Заранее благодарен!

ответ

5

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

Единственная причина - всерьез, только причина - что модель модели существует, чтобы моделировать представление. Имеются ли в представлении кнопки, запускающие команды? Команды принадлежат модели представления.

Думаю, «на самом деле ответственность за перенос Компонентов за запись» кажется разумной на его лице, но на самом деле это признак того, что вы теряете следы, почему вы даже создали модель представления в первую очередь. Есть ли в представлении «Компонент» кнопка «Вверх»? Затем модели Component view требуется команда «Вверх», к которой вы можете привязать кнопку. Потому что это то, что модель представления компонентов выглядит для.

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

1

Если ваша цель состоит в том, чтобы иметь команду на родительском ViewModel, который действует на элемент ребенка ViewModel, вы можете сделать это с помощью RelativeSource связывания по команде и передавая элемент в качестве параметра командной:

<DataTemplate DataType="{x:Type vm:ComponentViewModel}" > 
    <Button 
     Command="{Binding DataContext.RemoveCommand, 
      RelativeSource={RelativeSource AncestorType=ItemsControl}}" 
     CommandParameter="{Binding}" 
     Content="{Binding Name}"/> 
</DataTemplate> 

Связывание RelativeSource найдет элемент ItemsControl, поэтому свойство DataContext будет вашим RecordViewModel. CommandParameter будет индивидуальная ComponentViewModel, так что ваша реализация ICommand будет:

DeleteComponent((ComponentViewModel)parameter); 
1

это действительно запись, которая должна управлять Components позиции/удалить компонент, а не сам компонент

Что касается ваших моделей объектов, это, вероятно, так. Тем не менее, ViewModels - это все о представлении, а кнопки - часть презентации Component. Поэтому я думаю, что для ComponentViewModel может быть приемлемым ссылка на родительский RecordViewModel, чтобы включить этот сценарий, даже если было бы нецелесообразно ссылаться на его родительскую запись.

Но учтите, что в вашем сценарии, возможно, ComponentViewModel имеет слишком много обязанностей.Он принадлежит к коллекции (потому что он мутирует коллекцию), и он принадлежит элементу в коллекции (поскольку он показывает имя компонента в TextBox). Похоже, эта двойная ответственность вас беспокоит. Так сломайте это. Сделать RecordViewModel содержать RecordElementViewModels, каждый из которых знает, как удалить себя из записи; и каждый RecordElementViewModel содержит ComponentViewModel. С точки зрения зрения, это похоже на то, что ваш пользовательский интерфейс будет составлен таким же образом: внешняя панель с кнопкой «Удалить», а затем еще один элемент управления или панель внутри, представляющая свойства компонента.

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

0

Чтобы конкретно ответить на ваш вопрос о том, украшающих:

Вы получаете в изменении способа, которым DataTemplate-d элемент продуман, что означает, что вы не просто наслоение в Adorner на верхней части элемента, вам 'действительно хочет вставить панель в визуальное дерево, которое накладывает свой собственный макет на DataTemplate (который становится дочерним элементом новой панели). Я признаю, что я не пользовался украшателями, но, похоже, это не то, для чего они нужны.

Лучший способ сделать это, IMO, состоит в том, чтобы ваш DataTemplate генерировал родительскую панель, кнопки и все - что приводит к необходимости использования функций ComponentViewModel или, возможно, разделяет обязанности ComponentViewModel (см. Мой другой ответ) ,

Смежные вопросы