WPF: Украшаем ViewModel? - PullRequest
       18

WPF: Украшаем ViewModel?

0 голосов
/ 10 июля 2010

У меня есть следующие ViewModel: RecordViewModel, ComponentViewModel, где RecordViewModel, по сути, является контейнером для нескольких ComponentViewModel.

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

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

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

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

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

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

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

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

Заранее спасибо!

Ответы [ 4 ]

5 голосов
/ 10 июля 2010

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

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

Думать, что «ответственность за перемещение компонентов» лежит на Record, кажется разумным на первый взгляд, но на самом деле это признак того, что вы сбились с пути, почему вы даже создали представлениеМодель на первом месте.Есть ли в компонентном представлении кнопка «Переместить вверх»?Затем модели представления компонентов требуется команда «Переместить вверх», к которой можно привязать кнопку.Потому что именно так выглядит модель представления компонентов для .

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

1 голос
/ 10 июля 2010

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

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

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

Теперь, например,Вы написали, где представление Компонента - просто TextBox, я бы не стал делить ViewModel на две части.Но для более сложного примера это может иметь большой смысл.

1 голос
/ 10 июля 2010

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

<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);
0 голосов
/ 10 июля 2010

Чтобы конкретно ответить на ваш вопрос об украшении:

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

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

...