2012-06-12 2 views
3

Я изучаю MVVM.Где я могу назвать модель в ViewModel?

У меня есть два Просмотр заполнение выпадающих списков из свойств ObservableCollection в моей модели представления (например, свойство «OC1» & «OC2»). У меня также есть свойство привязанный к выбранному пункту OC1 (например, свойство «SelVal»), что OC2 зависит, поэтому, когда свойство SelVal изменяется, OC2 необходимо повторно получить его данные из базы данных.

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

Мое текущее решение:

получить аксессор OC2 запрашивает базу данных и устанавливает это личное поле для значения, возвращаемого из базы данных (который использует View). Поэтому, когда SETVAL меняется, я просто называю this.RaisePropertyChanged («OC2») в SETVALустановить аксессор Вид и просит OC2, который, в свою очередь, запрашивает базу данных и возвращает обновленный список , Проблема в том, что я не использую аксессуар get, для которого он предназначен, поскольку я назначаю его значение в нем. Но то, что мне нравится в этом, является самодостаточным (т. Е. Мне не нужен метод «BindOc2», который мне нужно будет вызвать в конструкторе, а затем снова в наборе SelVal ). Пожалуйста, порекомендуйте. И что лучше?

ответ

2

Ваше подозрение правильно, таким образом ломает модель MVVM и не использовать механизмы, которые могут упростить вашу работу, как триггеры в System.Windows.Interactivity, который доступный в Expression Blend SDK.

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

Лучшим решением является извлечение кода загрузки данных в отдельный метод, который может быть вызван командой или триггером. Этот метод либо изменит содержимое коллекции Oc2, либо просто заменит его новой коллекцией. В любом случае средство настройки свойств поднимет правильное уведомление, а второе комбо будет обновлено.

Следующий пример взят из fabien's answer в аналогичной С.О. вопрос:

<ComboBox x:Name="fileComboBox" ItemsSource="{Binding FileList, Mode=TwoWay}">     
     <i:Interaction.Triggers> 
      <i:EventTrigger EventName="SelectionChanged"> 
       <i:InvokeCommandAction 
         Command="{Binding SelectionChangedCommand}" 
         CommandParameter="{Binding SelectedItems,   
         ElementName=fileComboBox}"/> 
      </i:EventTrigger> 
     </i:Interaction.Triggers> 

    </ComboBox> 

Большинство фреймворков обеспечивают поддержку этой конструкции. Caliburn.Micro предоставляет actions, который будет вызывать метод ViewModel при возникновении события пользовательского интерфейса и синтаксис ярлыка, чтобы избежать записи триггера XAML и соответствующей команды. Он просто соединяет событие с методом ViewModel. XAML может быть столь же просто, как это:

<ComboBox x:Name="Oc1" 
    cal:Message.Attach="[Event SelectionChanged] = 
         [Action ReloadFor($this.SelectedItem)]" /> 

значение $this еще одна запись, которая ссылается на саму ComboBox.

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

<ComboBox ... SelectedItem={Binding CurrentOC2,Mode=TwoWay} /> 
+0

Ваше решение звучит мудро (особенно с Законом Мерфи). Вы предлагаете мне иметь отдельный метод для всех моих списков? Поскольку в предыдущем проекте, отличном от MVVM, у меня было более 10 методов (BindSites, BindNames, BindBusiness и т. Д.), И я в конечном итоге группировал их в другие методы инициализации и т. Д. - они, казалось, были излишне отделены от свойств. Но опять же, я никогда не разрабатывал большой проект, чтобы это было правильным способом ... – Steve

1

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

1

Так что, чтобы перефразировать, у вас есть что-то похожее на Категория, Текущую категорию и Подкатегорию. Когда CurrentCategory изменяется, SubCategory необходимо обновить.

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

+0

Thanks Kenneth. Когда вы говорите повсюду, это в крупных проектах? Потому что, как сказал Панайотис, однажды я захочу установить собственность, и я не смогу. – Steve

+0

Да в крупных проектах. Однако в крупных проектах модели просмотра обычно представляют только логику, предназначенную для представления (логика, связанная с неимитизмом, обычно реализуется в каком-то слое домена/бизнеса/услуги). Они обычно точно соответствуют функциональности ui. Если ui не позволяет вам устанавливать коллекцию подкатегорий, тогда обычно у меня нет публичного сеттера, который бы соответствовал моей модели. –

1

Если эти данные не изменяются, вы можете получить это в своей модели просмотра.

Всегда запрашивать базу данных не должен быть первым вариантом.

вы могли бы сделать это в довольно простым способом:

Dictionary<string, List<string>> cache; 
... 
List<string> subCat; 
if cache.TryGetValue (selVal, out subCat) 
{ 
    // no need to call database 
} 
else 
{ 
    // else call database 
    // insert result in cache 
} 
+0

Я попробую включить вашу идею Mare, ta. – Steve

2

Я понимаю ваше сдержанность с да, повышение PropertyChanged для другого свойства немного взломано, но это не так уж плохо ИМХО.

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

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

+0

Спасибо за ваш вклад Gaz. Проблема, которую вы выделили, является основной причиной, по которой я неохотно ставил db pull в SelVal setter. Может быть, это только я, но еще одна причина, по которой я имею в виду, что он не сразу прослеживается с Oc2, должен спускаться по дорожке, которую я забыл, я положил ее туда. – Steve