We once worked with WinForm and we had a certain class:

class City { public int ID {get;set;} public string Name {get;set;} public List<Area> {get;set;} .... } 

Then we learned about WPF and decided to go for it. But if it is WPF, then you need to do everything according to the canon (that is, using MVVM) and you should make a ViewModel. Duck here I get lost. How to do it better? To finalize the very same City class is to make it INotifyPropertyChanged (In this case, replace the collections with ObservableCollection ), but then we have the Model and ViewModel merged together? Not good, or good ?. Or create a ViewModel for it:

 class CityViewModel : INotyPropertyCjanged { private City _city; public int ID { get {return _city.ID; } set {_city.ID = value; RaisePropertyChanged("ID");} } ... } 

But what then to do with List<Area> ? How to pack it in ObservableCollection ?

Please direct the true path ... Examples are welcome!

UPD

And until I forgot. Suppose we need to fill our model with data from, for example, databases. Where should the data retrieval function be located? In ViewModel or View or else where?

  • the data acquisition function must be in a separate DataContext class that is passed to the Model - Acne

1 answer 1

See it.

Classes of the model are separate, and do not overlap with the classes of VM. VM classes model the essence of your “business logic,” that is, internal objects in terms of a program. Model classes model the essence of their subject area.

For example, the ID is interesting to the model, but it may not be at all interesting to the program, so transferring it to the VM does not make much sense (unless it is needed in the UI).

So we get this:

Model:

 class City { public int ID { get; private set; } public string Name { get; private set; } public List<Area> Areas { get; private set; } } static class CityHelpers { static City GetCityByName(string name) { ... } } 

VM:

 class CityVM : INotifyPropertyChanged // или даже DependencyObject { public CityVM(City city) { name = city.Name; Areas = new ObservableCollection(); foreach (var area in city.Areas) Areas.Add(new AreaVM(area)); } public Name { get { return name; } set { if (name == value) return; name = value; RaisePropertyChanged("Name"); } } public ObservableCollection<AreaVM> Areas { get; private set; } // ну и ещё имплементация INotifyPropertyChanged } 

The data acquisition functions are, of course, in the model: the VM should not know exactly how and where the data comes from. But to ask the model to load the data should be VM (and it is desirable to load them not in the UI-stream, of course, but it will hang).

  • I don’t think that this is the right decision to use the List in the model, because after updating the Areas list in the City model, the Areas list in CityVM also needs to be updated, I recommend using the ObservableCollection in the model right away and in the VM just make a property that returns the list from the model - Acne
  • There are a couple of questions: 1. How should the model know the coordinates of the repository? To transfer to it a class which "knows" or to fart coordinates (ConnectionString in a case with a DB)? 2. What if we work with already ready classes of models (we have no opportunity to bring them to the necessary functionality)? Wrap them in another class, which we will continue to use as a model? - Donil
  • one
    @ Acne: If the model data is "live", that is, they can change without a direct VM authorization, the model should have a means to notify about changes. For example, event or INotifyCollectionChanged . ObservableCollection can also be used in the model, but this is not always the best solution, since the ObservableCollection tied to a stream. - VladD
  • @Donil: the coordinates of the repository are the internal details of the model device, the “outside world” does not know anything about them. Let the ConnectionString be stored on the model, in one of the model classes. Or let it be stored in the configuration, and one of the model classes will get it from there (and in general it will be responsible for it). - VladD
  • 2
    @Donil: Yeah, he planned as a public one. You, as an architect, define the interface between the model and the VM. It is better to even plan it out on paper in advance, estimate the typical workflow, who is calling whom when, who is in charge of what, who knows what. - VladD