問題描述
關於服務參考和 MVVM 模式的幾個一般問題 (A few general questions about Service Reference and MVVM pattern)
There is a web service.
- It provides types
Zoo
andAnimal
. Zoo
has a dictionary of animal ids and names.Animal
has properties:Id
,Name
and(additional stuff)
.- It has a method
GetZoo
that returns a zoo object. - It has a method
GetAnimalStuffById
that returns anAnimal
object withId
,Name
and the(additional stuff)
.
So the idea is ‑ GetZoo
allows me to get a list of animal ids + names, and then GetAnimalStuffById
fetches full animal info.
I add a "service reference" to that service in VS and want to write a MVVM app. Some things I don't fully understand and need to be brainwashed about.
Is it OK for autogenerated classes to be my models?
Not related to the example, but anyway: what "collection type" should I specify when adding service reference? Is
ObservableCollection
an overkill and a bad practice for models?Say, user goes to an application page showing full animal info. Obviously, initially I have an
AnimalViewModel
with onlyId
andName
values (taken fromGetZoo
). As the page is navigated to, I callGetAnimalStuffById
and get anAnimal
object with all the data. What should I do next? Replace the DataContext of my view with a newAnimalViewModel
created from newAnimal
object (A), or just replace the values in it (B)?If the answer is (A), how do I replace the DataContext in all the views?
If the answer is (B), what should cause that update? Should the VMs subscribe to some fancy manager's event about getting an
Animal
update? Or is there some other approach?What is the purpose of
INotifyPropertyChanged
in the autogenerated classes? They are always returned fresh from the webservice in my case. Does Microsoft suggest to use them also as ViewModels in some scenarios?
Thanks.
‑‑‑‑‑
參考解法
方法 1:
Here are a few answers based on my own experience with MVVM (which may or may not be "best practice"..)
Absolutely! No need to do everything twice ‑ see #5 and #6 (although there are people who disagree here).
Yes, unless you actually need the functionality of an
ObservableCollection
server‑side, I would say it's overkill, and possibly confusing to others. Techincally, there's no overhead to the messages being sent across the wire, but I would go with something simpler, like an array.Go with option B.
‑
For example, you could have a single property in your
AnimalViewModel
to hold all the additional stuff:public Animal AdditionalData { ...
. Now, whoever callsGetAnimalStuffById
can just update the current ViewModel's AdditionalData with thatAnimal
object.I assume you already know that
INotifyPropertyChanged
is there to let the View know that some data has changed somewhere (if not, googling "inotifypropertychanged mvvm" should get you started). Now, connecting the dots from #1 and #5, your View can now bind to the animal's additional data by going through the AdditionalData property without having to recreate everything in the ViewModel:<TextBox Text="{Binding Path=AdditionalData.HeightOrWhatever}" />
.
Note: If your View isn't WPF or Silverlight, that last point won't make much sense..
方法 2:
And here's answers based on my experience (mainly to provide another point of view)
It's fine to autogenerate
Models
from an endpoint. But I would recommend POCOModels
without anyINPC
cruft. Two reasons, a) it makes theModels
simpler and easier to maintain and b) You won't be tempted to expose yourModels
directly to theView
, or if you do they won't work properly.Continuing on from #1, I would not use
ObservableCollection
inModels
. Again to keep things simple and to avoid presentingModels
directly to theView
.Option (B)
‑
All the properties in the
ViewModel
should implement INPC. Then when you change them the binding will automatically update. You can either have all theAdditionalData
values as properties of yourAnimalViewModel
which is flattening the data, or you can have anAdditionalDataViewModel
object to hold the extra data. To map data from anAdditionalData
object toAdditionalDataViewModel
consider using a mapping tool like AutoMapper or ValueInjecter.I don't know why the autogenerator added
INPC
stuff into your models. What tool are you using? In any case as I've said I do not recommend havingINPC
inModels
, or exposingModels
to theView
. Instead you should be mapping fromModels
toViewModels
and only exposingViewModels
to theView
.
(by Mikhail Orlov、Sphinxxx、Cameron MacFarland)