Ok, was will man denn eigentlich?
Man hat schon die Daten in einem Model wie z.B.
class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
und benötigt dazu ein ViewModel.
Microsoft sieht das so: Handarbeit!
class MsViewModel : INotifyPropertyChanged
{
private readonly Customer _customer;
public MsViewModel(Customer customer)
{
_customer = customer;
}
public string FirstName
{
get { return _customer.FirstName; }
set
{
if (value == _customer.FirstName)
return;
_customer.FirstName = value;
NotifyPropertyChanged(„FirstName“);
}
}
public string LastName
. . .
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler == null)
return;
handler(this, new PropertyChangedEventArgs(name));
}
#endregion
}
Das ist Fleißarbeit, Fehleranfällig, nicht refakturierbar, ätzend, usw..
Alternativ könnte ein Codegenerator geschrieben werden – mir persönlich nicht ausreichend. Ich würde das gerne so sehen:
class MyViewModel : DynamicViewModel<Customer>
{
}
Weitere Ziele der Entwicklung:
- Blendability (Bindungen werden in Expression Blend angezeigt)
- Automatisches INotifyPropertyChanged
- Mehrere Modelle können in einem ViewModel zusammengefasst werden
- Zusätzliche Properties als Ergänzung zu denen des/der Models
- Aktualisierung voneinander abhängiger Properties
- Filterung der Properties (nicht alle werden dem View bereitgestellt
Los gehts. Erst mal die Grundfunktion, also die Properties des Models im View bereitstellen.
Der erste Ansatz ist ExpandoObject – geht aber nicht weil sealed, eine Schutzbehauptung im Sinne von: Oh, das ist schon gut, aber ob es so bleiben kann weiß ich noch nicht 
Also direkt von DynamicObject ableiten. Mehr Arbeit aber geht – fast. Der Designer kann jetzt die Bindungen nicht mehr Anzeigen.
Blendability
Eine Hauptforderung ist, dass das Ergebnis mit Expression Blend bearbeitet werden kann. Ohne dies ist die Zusammenarbeit mit einem Designstudio nicht möglich. Leider ergab diese Forderung die ersten Probleme.
Die Lösung ist die zusätzliche Implementierung von ICustomTypeDescriptor.
Automatisches INotifyPropertyChanged
Ergibt sich ganz einfach in der Implementierung von TrySetMember aus DynamicObject.
Mehrere Modelle
Im einfachsten Fall basiert ein ViewModel nur auf einem Model. Aber schon eine einfache Beziehung erfordert die Bindung an mehrere Modelle (z.B. Person und Firma).
Die Implementierung als Generic ist für diesen Fall nicht flexibel genug.
DynamicViewModel<Customer>
Ich habe mich deshalb entschieden eine Methode AddModel einzuführen. Daraus ergibt sich außerdem der Vorteil, dass bereits vorhandenen Instanzen des Models im ViewModel verwendet werden können.
Zusätzliche Properties
Als Ergänzung zu den Properties des Models können im angeleiteten ViewModel neue Properties eingeführt werden. Ich habe hierbei zwei Varianten implementiert.
class MyViewModel : DynamicViewModel
{
public string MyProp { get; set; }
Die public Properties der Ableitung stehen ganz normal zur Verfügung. Mit automatischer Unterstützung von INotifyPropertyChanged!!!
Außerdem können “noch dynamischer” über einen Indexer zur Laufzeit hinzugefügt werden.
public object this[string name]
this[„Test“] = „kuckuck“;
Werden diese im Konstruktor hinzugefügt stehen sie auch im Designer zur Verfügung!!!

Aktualisierung voneinander abhängiger Properties
Im speziellen ViewModel will man gewöhnlich weitere, aus den Daten des zugrunde liegenden Models berechnete Properties bereit stellen. Hierbei gibt es folgende Probleme. Erstens ist zur Kompilierzeit der Typ der/des Models nicht bekannt. Der Zugriff muss also über den Indexer erfolgen (nicht schön, ich bin noch am Grübeln). Außerdem muss zur korrekten Weiterleitung von INotifyPropertyChanged bekannt sein, auf welchen Properties das neue basiert. Hierzu wird das Attribut DependsOn verwendet. Gibt es schon im Framework, muss aber hier für die eigenen Zwecke auch selbst implementiert werden.
[DependsOn(„FirstName“)]
public int LenOfFirstName { get { return this[„FirstName“].ToString().Length; } }
Filterung der Properties
Um nicht alle Properties des Models im Designer sichtbar zu machen können die zu versteckenden mit dem Browsable(false) Attribut gekennzeichnet werden.
[Browsable(false)]
Gibt es auch schon im Framework, muss aber auch hier für die eigenen Zwecke auch selbst implementiert werden.
Fazit
Für den ersten Moment bin ich mit der Funktionalität sehr zufrieden.
Auf dem OpenSpace im Juli in Karlsruhe werde ich auf jeden Fall eine Runde darüber diskutieren…