ViewModel против ValueConverter для составных привязок - PullRequest
1 голос
/ 29 июля 2011

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

(заявление об отказе: я уже видел некоторые вопросы, подобные этому, но пока еще не видел ничего, учитывающего преимущества / недостатки в изменении типов данных специально для представления. Извинения, если я пропустил что-то большое, но каждая третья веб-страница кажется где-то есть "MVVM" = p)

Выпуск: Пользователи должны выбрать продолжительность для действия. они могут либо выбрать кратную длительности активности по умолчанию (она же BlockSize), либо для этих «особых случаев» мы разрешаем им отменять это и выбирать из 5-минутных интервалов.

для пользовательского интерфейса, мы решили использовать для этого комбинированный список и тумблер. по умолчанию в поле со списком будет отображаться {"1 блок", "2 блока", "3 блока"}, или когда флажок "Custom Duration" установлен: {"5 минут", "10 минут", "15 минут" }

3 Возможные решения: В идеале (для расширяемости) ViewModel предоставляет ObservableCollection<TimeSpan> для привязки своего Combobox. Но в этом случае, как я должен суффикс "Block / s" или "Minute / s". Будет работать одноразовый многозначный преобразователь, но это создаст много шаблонного кода, и я не большой поклонник того, сколько проверки типов вы должны реализовать, поскольку они не являются строго типизированными.

Альтернативой является использование ViewModel для показа ObservableCollection<string>, но в этом случае мне нужно написать метод для преобразования "3 Blocks" => new TimeSpan( 0, 3 * BlockSize, 0 ), который звучит более привлекательно, чем MultiConverter. В этом случае это довольно простое сопоставление 1-1, но даже при этом у меня возникнет соблазн создать 4 свойства и метод для управления им. Это похоже на выделение кода для управления одной привязкой.

private Dictionary<string, TimeSpan> selectedDurationMap { get; set; }
private ObservableCollection<string> availableCustomDurations { get; set; }
private ObservableCollection<string> availableBlockDurations { get; set; }
public ObservableCollection<string> AvailableDurations { get; private set; }

private fillDurationLists( TimeSpan maximumDuration, TimeSpan blockDuration ) { }

другой вариант - иметь несколько ComboBox, которые отображаются / скрываются в зависимости от того, выбран ли ToggleButton «Пользовательская продолжительность». Оба могут использовать встроенный StringFormat для добавления «блоков» или «минут», в то время как я могу сохранить свои доступные длительности в формате TimeSpan. Это решение, которое я до сих пор предпочитал, но хотя простая реализация ставит все флажки, оно не очень расширяемое

например, чтобы добавить контроль над множественностью (блок против блоков), мне понадобится ValueConverter, в этом случае решение 1 является более расширяемым, читаемым и эффективным (половина визуальных элементов) при достижении той же цели с меньшим количеством кода ( хорошо, это небольшая проблема с игрушкой, но это довольно типичный сценарий, который я испытываю)

1 Ответ

1 голос
/ 29 июля 2011

Есть еще одно решение, которое я бы предпочел, и это выставить ObservableCollection моделей представлений на время. Оберните ваш TimeSpan в маленький класс ViewModel, который выдает свое имя (например, «1 блок») через ToString() или свойство.

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

...