Reputation: 2857
There is a web service.
Zoo
and Animal
.Zoo
has a dictionary of animal ids and names.Animal
has properties: Id
, Name
and (additional stuff)
.GetZoo
that returns a zoo object.GetAnimalStuffById
that returns an Animal
object with Id
, 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 only Id
and Name
values (taken from GetZoo
). As the page is navigated to, I call GetAnimalStuffById
and get an Animal
object with all the data. What should I do next? Replace the DataContext of my view with a new AnimalViewModel
created from new Animal
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.
Upvotes: 2
Views: 331
Reputation: 71856
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 POCO Models
without any INPC
cruft. Two reasons, a) it makes the Models
simpler and easier to maintain and b) You won't be tempted to expose your Models
directly to the View
, or if you do they won't work properly.
Continuing on from #1, I would not use ObservableCollection
in Models
. Again to keep things simple and to avoid presenting Models
directly to the View
.
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 the AdditionalData
values as properties of your AnimalViewModel
which is flattening the data, or you can have an AdditionalDataViewModel
object to hold the extra data. To map data from an AdditionalData
object to AdditionalDataViewModel
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 having INPC
in Models
, or exposing Models
to the View
. Instead you should be mapping from Models
to ViewModels
and only exposing ViewModels
to the View
.
Upvotes: 1
Reputation: 13017
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 calls GetAnimalStuffById
can just update the current ViewModel's AdditionalData with that Animal
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..
Upvotes: 1