Forgive the title - I really can't thnk of a more succinct way to put it.
Alright, first of all I am creating a WPF application using C# and MVVM, in Visual Studio 2010.
It's a language program, and my data model has in it some inheritance. A LanguageItem sits at the top. On step down is GeneralVocabItem and then two classes derive from that: Verb and IAdjective. I keep a list of these in XML and I load them all into a list of LanguageItem.
So now to the view model part. I looked up already how to handle view models when the view models represent classes with inheritance. I always thought it looked tricky, but I've managed to avoid it thus far. The suggestion I read here, on Stackoverflow was to use generics and an abstract base class. So this is what I tried to do.
So the base ViewModel is as follows:
public abstract class LanguageItemViewModelBase<TModel> : ObservableObject
{
private readonly TModel _dataObject;
protected TModel DataObject { get { return _dataObject; } }
public LanguageItemViewModelBase(TModel dataObject)
{
_dataObject = dataObject;
}
}
Then I had view models for the classes I wanted. The view model for LanguageItem looks like this:
class LanguageItemViewModel : LanguageItemViewModelBase<LanguageItem>
{
public LanguageItemViewModel(LanguageItem item) : base(item)
{
}
public int ItemID
{
...
}
public int ItemType
{
...
}
}
and the view model for Verb looks like this:
class VerbViewModel : LanguageItemViewModelBase<Verb>
{
public VerbViewModel(Verb item) : base(item)
{
}
public int ItemID
{
...
}
public int ItemType
{
...
}
}
Now, what I wanted was a list which could hold any of these view models within it.
The List I declared as follows:
private ObservableCollection<LanguageItemViewModelBase<LanguageItem>> _languageItemVMs = new ...
Now this here might be where my mistake is. Can I have a list of an abstract class like this? And am I limiting myself by assigning the type, or is it okay because all types (for the generic type) derive from LanguageItem anyway? So this part I don't know. Honestly, the territory is already getting a little murky.
Anyhow, when I load a LanguageItem from XML, there is an event handler for my list of view models. It looks like this:
Database.Instance.RegisterForLanguageItemAdded(
(Object o) =>
{
// o is some kind of LanguageItem
if (o != null)
{
LanguageItem l = (o as LanguageItem);
LanguageItemViewModel lvm = new LanguageItemViewModel(l);
LanguageItemVMs.Add(lvm);
}
});
Now, this works okay kind of. I created a ListBox to test this list and all the items appeared, showing the properties. However, at that stage the view models had all the same exposed values (ItemID and ItemType). As a test, I changed VerbViewModel so it exposed an additional property that was not exposed in LanguageItemViewModel. It did not appear. Perhaps, I thought, it is because I am specifically adding a LanguageItemViewModel to my view model list in the event handler above. So in order to test this, I also added a random VerbViewModel to the list in the event handler.
That looked as follows:
Verb v = new Verb();
v.ItemID = 100;
v.ItemType = Static_Enums.StaticLanguageItemTypesEnums.TYPE_VERB;
VerbViewModel vvm = new VerbViewModel(v);
LanguageItemVMs.Add(vvm);
I thought if I specified the type, it might work out.
Unfortunately I get a compile error telling me that 'argument 1 cannot be converted from VerbViewModel to LanguageItemViewModelBase<LanguageItem>'.
So honestly at that stage I thought I'd come and ask here. It might be that the entire organisation is wrong and so worrying about this end part is pointless since it can never work. I might be labouring entirely under some false assumptions and misunderstandings that someone with more experience and knowledge could help me with.
Does the view model list need to be a non abstract type? Does the fact that the generic types accepted by the view models inherit from each other cause too many problems? I mean the view models inherit from each other, but the generic type does too. Honestly it's a bit of a headache really when it comes to trying to have them all in one list. Can it be done? Is there a better / simpler / more easy to understand way?
Well, thanks for reading. I hope I can get some useful tips on this one.