Работа с объектами WPF внутри ViewModel - PullRequest
2 голосов
/ 05 марта 2010

Используя шаблон MVVM для создания приложений WPF, у вас есть ViewModel, предоставляющая данные для View. Я столкнулся с ситуацией, когда я считаю целесообразным создавать объекты WPF в моей ViewModel, и View выбирает их и показывает их. Более конкретно, у меня есть функциональность для рисования, где мне нужно хранить InkPresenter в конце. Я получаю жесты мыши в коде позади представления, но передаю события в ViewModel. ViewModel обрабатывает событие мыши и создает объекты чертежа, которые помещаются в коллекцию ObservableCollection, так что View может их извлекать и отображать.

Вопрос в том; Это нормально, или это плохая практика для создания объектов WPF в классах ViewModel? И почему? Если все в порядке; Есть ли лучшие практики или рекомендации по работе с этими объектами?

Ответы [ 2 ]

2 голосов
/ 05 марта 2010

Я столкнулся с интересным случаем для этого только сегодня. Я создаю пользовательский интерфейс, который включает в себя коллекцию FlowDocument s. Эти элементы представлены в виде ListView, один из шаблонов ячеек которого RichTextBox.

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

Все было хорошо, пока я не реализовал переупорядочение коллекции методом перетаскивания. Здесь я обнаружил одну из причин , почему Document не DP. Изменение порядка коллекции на самом деле не меняет порядок объектов, к которым они привязаны; перемещенные элементы просто обновляют свои цели привязки. И слава Богу, если FlowDocument принадлежит одному RichTextBox, вы не можете назначить его другому. Изменение порядка этих FlowDocuments нарушает пользовательский интерфейс, что является проблемой, поскольку единственная причина, по которой я делаю этот пользовательский интерфейс, в первую очередь, заключается в переупорядочении этих элементов.

Молоток, которым я решил поразить это, состоял в том, чтобы сделать RichTextBox свойством моей модели вида. Таким образом, когда я перемещаю FlowDocuments в коллекции, RTB, владеющие ими, перемещаются вместе с ними.

Лично я не представляю, является ли этот класс тестируемым на модуле. Это не то, что делает это неправильным ответом.

Что делает этот неправильный ответ тем, что теперь, когда я поместил этот компонент в свой класс, он больше не является частью системы маршрутизации событий. Если я изменю FontFamily в своем стиле FlowDocument в приложении, эти элементы управления никогда не услышат об этом. Я также не могу ничего связать с ними. (По крайней мере, нелегко.) Возможно, есть другие проблемы, которые я еще не обдумал.

Я не совсем уверен, каким будет правильный ответ в моем случае. Я думаю, что мне, возможно, придется починить мой привязываемый RichTextBox, чтобы он поддерживал два FlowDocument объекта: тот, который выставлен миру с помощью Document геттера и сеттера, и тот, который находится внутри элемента управления сам. (То есть, когда что-то устанавливает свойство Document для объекта, оно сохраняет это значение в своем закрытом поле, а затем копирует содержимое документа в содержимое свойства base Document.)

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

2 голосов
/ 05 марта 2010

Нет, это "не хорошо" (цитаты, как я говорю о передовых практиках - говорить, что ViewModel - это не ViewModel, потому что это неправильно) создавать и ссылаться на классы WPF (Control-) внутри ваших ViewModels.

При попытке выполнить тестирование модели ViewModel возникают очень большие недостатки: элементы управления нуждаются в специальных обработках и представляют нежелательные зависимости.

Вы должны только передавать фактические «данные» этих объектов в ViewModel: для примера с InkPresenter это будет O.k. по моему мнению, чтобы отправить ViewModel StylusPoints, но не сам InkPresenter. Еще лучше было бы классы ViewModel, представляющие StylusPoints - они могут быть сопоставлены с фактическими StylusPoints с помощью привязки данных (я не знаю, возможно ли это с InkPresenter) или с помощью некоторых посредников (например, с использованием прикрепленных свойств).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...