My question is: How to manage an inheritance chain of viewmodels?
My situation:
I'm having a standard ViewModelBase which only implements the INotifyPropertyChanged interface.
Furthermore I have a BusinessObjectViewModel which has a Guid, a PersonBaseViewModel which has the persons core data, a CustomerViewModel with customer related stuff and a EmployeeViewModel with employee related stuff.
All viewmodels certainly encapsulate a modelobject (Customer, Employee, PersonBase).
BusinessObjectViewModel inherits from ViewModelBase
PersonBaseViewModel inherits from BusinessObjectViewModel
CustomerViewModel inherits from PersonBaseViewModel
EmployeeViewModel inherits from PersonBaseViewModel
The model comes via constructor into the viewmodel.
If I use a constructor chain (every viewmodel makes a call to the base constructor) every viewmodel has it's model to return the encapsulated values from the model.
But I got to have a Model property in every viewmodel. In the case of CustomerViewModel I would have a reference in CustomerViewModel, one in PersonBaseViewModel and one in BusinessObjectViewModel for one and the same object. That sounds stupid to me.
Or I have to cast every property access in the upper viewmodels.
p.s. this is just a small cut-out of my model hierarchy.
Thanks in advance.
If BusinessObject and Person classes (and their VM counterparts) are abstract, then you could access the right Model like this:
public abstract class BusinessObjectViewModel : ViewModelBase
{
protected abstract BusinessObject BusinessObject { get; }
protected BusinessObject Model { get { return this.BusinessObject; } }
}
public abstract class PersonViewModel : BusinessObjectViewModel
{
protected abstract Person Person { get; }
protected new Person Model { get { return this.Person; } }
protected override sealed BusinessObject BusinessObject
{
get { return this.Model; }
}
}
public class CustomerViewModel : PersonViewModel
{
protected new Customer Model { get; set; }
protected override sealed Person Person
{
get { return this.Model; }
}
}
public class EmployeeViewModel : PersonViewModel
{
protected new Employee Model { get; set; }
protected override sealed Person Person
{
get { return this.Model; }
}
}
This way every derived VM class provides a value for its base VM Model property by implementing abstract property and hides a base class Model property, so every VM works with Model property of an appropriate type (so no casting is required).
This approach has its benefits and drawbacks:
Benefits:
No casting involved.
Drawbacks:
Works only if base classes (BusinessObjectViewModel and PersonViewModel) are abstract because there must exist an abstract property that is implemented by the derived class and provides a Model instance to these base classes.
Model property should not be accessed in the base class constructors, because constructor chaining goes from base class to the most derived class. The most derived class constructor will set Model, so base class constructors are called to early to see it. This can be avoided by passing Model as a parameter through constructors.
BusinessObject and Person properties are unnecessary seen by the derived classes. EditorBrowsableAttribute might help here for Intellisense, but only when code is used by another assembly in different Visual Studio solution (this is Visual Studio specific behavior).
Performance. When base classes access Model, code will go through a chain of virtual properties. But since since implemented abstract properties are marked as sealed, virtual table lookup should not be so much performance degrading.
Doesn't scale nicely. For deep class hierarchies code would contain many unnecessary members.
Another approach would be:
public class BusinessObjectViewModel : ViewModelBase
{
protected BusinessObject Model { get; private set; }
public BusinessObjectViewModel(BusinessObject model)
{
this.Model = model;
}
}
public class PersonViewModel : BusinessObjectViewModel
{
protected new Person Model { get { return (Person)base.Model; } }
public PersonViewModel(Person model)
: base(model)
{
}
}
public class CustomerViewModel : PersonViewModel
{
protected new Customer Model { get { return (Customer)base.Model; } }
public CustomerViewModel(Customer model)
: base(model)
{
}
}
public class EmployeeViewModel : PersonViewModel
{
protected new Employee Model { get { return (Employee)base.Model; } }
public EmployeeViewModel(Employee model)
: base(model)
{
}
}
Benefits:
Base classes do not need to be abstract.
Model can be accessed through base class constructors.
No unnecessary additional properties.
Drawbacks:
Casting.
Based on this analysis, I would go with a second option because fixing its only drawback, casting performance, would be unnecessary micro-optimization that would not be noticeable in WPF context.
The simplest answer IMO is to use Generics, which might be as simple as
public abstract class ViewModelBase<TModel> TModel : class{
public TModel Model { get; protected set; }
}
The .net typing system will the know that your TModel is a Person, Customer, or whatever else without casting.
Let me know if you need more or if you want to post some code that needs help. And yes, it can be tricky getting your supertype heirarchies just right at first.
HTH,
Berryl
If you just want to expose your Model property in your ViewModels then you don't need to re-declare the Model properties in the ViewModel to expose them. I normally expose the underlying Model object as a property in my ViewModels. In your case, for example in your EmployeeViewModel you would have a:
private Employee _MyEmployee;
public Employee MyEmployee {
get
{
return _MyEmployee;
}
set
{
_MyEmployee = value;
NotifyPropertyChanged(x=>x.MyEmployee);
}
Then your View could bind to your Employee properties through the MyEmployee property exposed in the ViewModel. As far as I understand it, the only case when you want to re-declare or wrap your Model Properties in your VM is when you need to do some data manipulation to be presented to your view.
Related
I have two typed interfaces
public interface IComponentAreaModel<T>
public interface IComponentAreaViewModel<T>
The interface for the view model has a property 'Model' defined which is of the type of the interface for the model:
IComponentAreaModel<T> Model { get; }
In my actual implementation I have a model that implements the 'IComponentAreaModel' interface which works fine:
public class ArticleModel : IComponentAreaModel<Article>
Then I implement the view model as follows:
public class ArticleViewModel : IComponentAreaViewModel<Article>
{
public ArticleModel Model { get; }
}
And here the compiler tells me that the member 'Model' does not have the matching return type. To fix this, I would have to implement the view model as follows:
public class ArticleViewModel : IComponentAreaViewModel<Article>
{
public IComponentAreaModel<Article> Model { get; }
}
But this sucks as my ArticleModel class has some additional methods and stuff that are not part of the IComponentAreaModel. So when I wanted to use these methods through the property within my ArticleViewModel, then I would have to cast the interface object to the actual object.
Is there a way to tell the compiler that my ArticleModel implements the IComponentAreaModel and therefore is sufficient as Model for the IComponentAreaViewModel?
It depends on how do you use these interfaces. At least, there are three options.
Option 1. Use field inside implementation:
public class ArticleViewModel : IComponentAreaViewModel<Article>
{
// use this field, when you need ArticleModel
private readonly ArticleModel model;
// TODO: initialize model somehow
public IComponentAreaModel<Article> Model => model;
}
Option 2. Use explicit interface implementation:
public class ArticleViewModel : IComponentAreaViewModel<Article>
{
// use this property, when you need ArticleModel
public ArticleModel Model { get; }
IComponentAreaModel<Article> IComponentAreaViewModel<Article>.Model => Model;
}
Option 3. Add the 2nd type parameter to view model interface. Will add complexity, especially if you want to use IComponentAreaViewModel<> with another generic types:
public interface IComponentAreaViewModel<T, TModel>
where TModel : IComponentAreaModel<T>
{
TModel Model { get; }
}
public class ArticleViewModel : IComponentAreaViewModel<Article, ArticleModel>
{
public ArticleModel Model { get; }
}
What is the "C# way" to pass arguments of inherited class constructors to base class constructors? Would this require that I override the base_model string in the base class?
// Base class
class vehicle
{
private string base_model = String.Empty;
vehicle(string model)
{
this.base_model = model;
}
}
// Inherited classes
class tesla : vehicle
{
private readonly string model = "Model S"; // This is unchanging
tesla(string model) : base ( **pass model to base_model** )
{
// Initialize
}
}
class ferrari : vehicle
{
private readonly string model = "458 Spider"; // This is unchanging
ferrari(string model) : base ( **pass model to base_model** )
{
// Initialize
}
}
Edit
#JohnLBevan brought another question to my attention:
This brings to mind another question: is it possible to have no constructor arguments for the tesla class (or the ferrari class for that matter) and automatically pass the model variable (i.e. "Model S") to the base_model?
A far more OO standards compliant way to do this is to use an abstract property. This means the base class has defined the property but the extending classes must implement it. This also means you cannot directly create an instance of vehicle, instead you must create one of the derived types.
abstract class vehicle
{
vehicle() { }
public abstract string Model { get; }
}
// Inherited classes
class tesla : vehicle
{
private readonly string model = "Model S"; // This is unchanging
public override string Model { get { return model; }}
}
class ferrari : vehicle
{
public override string Model { get { return "458 Spider"; }}
}
The only time you really want to be passing values from derived constructors to base constructors is when those values are actively used in the base class. This is a normally when you've overridden a base constructor, or you are using a dependency injection or dependency resolution pattern. The base class should not act as an aggregation of information from the derived class.
Exactly what you've done, only putting the variable name in where you had the asterisks:
// Inherited classes
class tesla : vehicle
{
private readonly string model = "Model S"; // This is unchanging
tesla(string model) : base ( model )
{
// Initialize
}
}
You also need to ensure that the base class's constructor is visible to its subclasses (i.e. is not private)
// Base class
class vehicle
{
private string base_model = String.Empty;
protected vehicle(string model)
{
this.base_model = model;
}
}
I am writing a library and my clients using my library.
My clients creates own classes derived from my base class.
Can i detect my client's class property is changed?
I don't want my clients to implement INotifyPropertyChanged.
I am also using reflection for other purposes. Why reflection can't detect properties change status?
My library code:
public class BaseClass
{
public void ChildPropertyChanged(propinfo...)
{
...
}
}
Client's code:
public class MyClass : BaseClass
{
public string Name {get;set;}
}
Your clients must collaborate, meaning they will have to write code to help you catch the change of properties, as in INotifyPropertyChanged clients (implementers) must raise an event (RaisePropertyChanged);
If you think about it, if what you are asking was possible, than INotifyPropertyChanged was not necessary..
One possible solution for you is to define an event in the base class, and guide your clients to raise it in their properties getters, or even better - calling a base class handler method.
You could implement the template pattern.
Base class.
public class BaseClass
{
protected string name;
private void NameChanged()
{
...
}
public void SetName(string value)
{
this.name = value;
this.NameChanged();
}
}
Derived class:
public class MyClass : BaseClass
{
public string Name
{
get
{
return this.name;
}
set
{
this.SetName(value);
}
}
}
Although doing it this way eliminates the need for the property in the derived class - it can be changed using the base class method SetName.
Sorry for the confusing title of the question. I am uncertain about how should I implement ViewModels and Models which derive from a base class.
My ViewModel classes are based on a ViewModelBase, the ViewModelBase holds a ModelBase which serves as a base class for all other models.
Each ViewModel holds a "Model" Property, however, because a Model property was defined by the base ViewModel class as the ModelBase class, I always have to create another property which casts the Model - from ModelBase to the relevant Model class.
My question is - is there not a simpler solution? Is there a design pattern which is relevant for these issues?
Here's a code sample:
public abstract class BasicViewModel : ViewModelBase
{
public BasicViewModel()
{
}
public ModelBase Model { get; set; }
}
public class ModelBase
{
}
public class ContainableViewModel : BasicViewModel
{
public ContainableViewModel(ContainableModel model)
{
this.Model = model;
}
public ContainableModel MyModel { get { return (ContainableModel)Model; } }
public int Children { get { return MyModel.Children; } set { MyModel.Children = value; } }
}
public class ContainableModel : ModelBase
{
public ContainableModel()
{
Children = 2;
}
public int Children { get; set; }
}
As you can see, the "MyModel" property is the one which bugs me.
Thank you very much for your help and time!
If each of your view model contains a Model property, you could use generics:
public abstract class BasicViewModel<TModelType> : ViewModelBase
where TModelType : ModelBase
{
public BasicViewModel(TModelType model)
{
Model = model;
}
public TModelType Model { get; set; }
}
public class ModelBase
{
}
Your containable view model is now defined as follows:
public class ContainableViewModel : BasicViewModel<ContainableModel>
{
public ContainableViewModel(ContainableModel model)
: base(model)
{
}
// you can now omit this method, it is defined on the abstract superclass
//public ContainableModel Model { get { return ()Model; } }
public int Children { get { return MyModel.Children; } set { MyModel.Children = value; } }
}
public class ContainableModel : ModelBase
{
public ContainableModel()
{
Children = 2;
}
public int Children { get; set; }
}
I generally don't use a base class for the different Model types, as there is generally not a one to one correspondance between ViewModel and Model objects. Further, the Model objects generally don't have much in common. This is different from the ViewModel objects, which all tie in via data binding and therefore could benefit from various helper methods that standardize the way you bind to your ViewModel instances.
The 'Model' in Model-View-ViewModel is a layer which provides your business logic and data interaction (everything not related to visualization and interaction with the user.) Your CustomerViewModel for your CustomerWindow might make use of a Customer object from your Model layer, but it very likely has references to other objects from your model, like some sort of Repository. Other Views, like say your MainWindow, might have a MainViewModel that doesn't directly correspond to any Model object, but probably has at least a few dependencies on your Model.
I have this code and I want to keep it elegant.
I got stuck at this inheriting issue and I would have to mess up the code if I do.
Help me keep it elegant. I don't mind making changes anywhere up and down the hierarchy; feel free to change the core.
I have these abstract classes (I omitted unrelated implementation to keep the question content short).
public abstract class Entity : IComparable
{
protected int _ID;
public abstract int ID { get; }
}
public abstract class SortedEntities<T> : IEnumerable<T> where T : Entity
{
Dictionary<int,T> _Entities;
}
And, obviously, an example of inheritance is as follows:
public class Contact : Entity { }
public class Contacts : SortedEntities<Contact> { }
And I also have more than just Contact and Contacts that inherit from Entity and SortedEntities that all act in the same manner.
At some point in my app, I want to select entities based on and ID list.
A sample code of what I want is:
Contacts LoadedContacts = new Contacts(); // load and fill somewhere else
// !!!NOT IMPLEMENTED YET!!!
Contacts SelectedContacts = LoadedContacts.GetFromIDList("1,4,7");
Where it returns a new Contacts object filled with those Contact objects of the ID's provided.
So, to allow that code for all classes inheriting from SortedEntities, I thought of adding this imaginative code to the abstract:
public abstract class SortedEntities<T> : IEnumerable<T> where T : Entity
{
// !!!NOT REAL CODE YET!!!
public abstract this<T> GetFromIDList(string IDCSV)
{
List<string> idlist = IDCSV.Split(',').ToList<string>();
return this.Where(entity => idlist.Contains(entity.ID.ToString()));
}
}
But obviously the this<T> is not allowed.
What I'm trying to tell the compiler is to make the return type of this method that of the inheriting class down the hierarchy.
That way, if someone calls LoadedContacts.GetFromIDList("1,4,7") it will return Contacts without having to cast it from SortedEntities<T> if I make it the return type, which would also require me to override the method in each inheriting class to hide the abstract method.
Am I forgetting something I already know?
Or is this completely not possible and I have to override and hide the method down the hierarchy for all inheriting classes?
A common solution is to add another generic type parameter that refers to the "current" type (like this refers to the "current" object):
public abstract class Entity : IComparable
{
protected int _ID;
public abstract int ID { get; }
}
public abstract class SortedEntities<TEntities, TEntity> : IEnumerable<TEntity>
where TEntities : SortedEntities<TEntities, TEntity>, new()
where TEntity : Entity
{
Dictionary<int, TEntity> _Entities;
public TEntities GetFromIDList(string IDCSV)
{
List<string> ids = IDCSV.Split(',').ToList<string>();
return new TEntities
{
_Entities = this.Where(entity => ids.Contains(entity.ID.ToString()))
.ToDictionary(e => e.ID)
};
}
}
Usage:
public class Contact : Entity
{
}
public class Contacts : SortedEntities<Contacts, Contact>
{
}
Note how the TEntities is restricted to a SortedEntities<TEntities, TEntity>. This does not really mean that TEntities can only refer to the current class, but as long as you follow the pattern of letting class X inherit from SortedEntities<X, Y>, it should work.
The new() constraint is required so you can instantiate a new instance of the "current" class.
Eric Lippert has indicated somewhere else that he dislikes this pattern. Act at your own risk!