Inside ASP.NET Databinding - Teil 2
Autor: Alexander Jung
Das Databinding eines ASP.NET DataGrids ist sehr leistungsfähig, insbesondere im Zusammenhang mit DataSets. Wie es im Detail funktioniert und wie Sie bei Bedarf eingreifen können ist auf den ersten Blick aber alles andere als offensichtlich. Dieser Artikel untersucht die grundlegende Arbeitsweise des Databindings und stellt die Eingriffsmöglichkeiten vor.
Teil 1: Datenbindung im Detail untersucht
In Teil 1 ging es um die Frage, wie das Databinding grundsätzlich funktioniert und welche Einriffsmöglichkeiten das .NET Framework bietet. Damit sollte das grundsätzliche Zusammenspiel zwischen den beteiligen Klassen, Objekten und Interfaces - speziell System.ComponentModel.ITypedList, System.ComponentModel.ICustomTypeDescriptor und System.ComponentModel.PropertyDescriptor - klar sein.
In diesem Teil soll als Beispiel ein Databinding an XML ohne Umweg über ein DataSet umgesetzt realisiert werden. Inwieweit das für sich gesehen Sinn macht, mag jeder selbst entscheiden. Die Sinnfrage wird gleich noch gestellt werden. In jedem Fall kann das Vorgehen aber als Kochrezept für jeden dienen, der etwa eigene Objektstrukturen auf diese Weise anbindbar machen möchte.
Databinding an XML ohne Umweg? Klingt gut, aber wozu? Wozu in anderen Fällen eingreifen? DataSets (System.Data.DataSet) bieten eine ganze Menge, selbst hierarchische Daten lassen sich anbinden (nachzulesen in "Geschachtelte Daten darstellen"). Und eigene Objektbäume lassen sich per Serialisierung auf XML und damit ebenfalls auf DataSets abbilden.
Nur leider ist ein DataSet nicht allmächtig. Im Bereich von XML gehen etwa Namespaces verloren oder eine existierende XML-Struktur will sich partout nicht mit dem DataSet vertragen. Als Beispiel wird folgendes Dokument mit der Exception "System.ArgumentException: The same table (Telefon) cannot be the child table in two nested relations." abgelehnt:
<root>
<Adressen>
<Person>
<Name>Jung</Name>
<VorName>Alexander</VorName>
<Telefon>0177/4711</Telefon>
<Telefon>06109/5077-0</Telefon>
</Person>
<Firma>
<Name>NEW LINE Software Development GmbH</Name>
<Telefon>06109/5077-0</Telefon>
</Firma>
</Adressen>
</root>
Einen Fehler kann man auch provozieren, indem man einem Attribut und einen untergeordneten Element den gleichen Namen gibt.
Auch für Objekte ist eine Serialisierung der Daten nach XML nicht unbedingt ideal.
Ein Objekt besteht aus wesentlich mehr, als nur aus seinen Daten. Das Verhalten
geht im DataSet aber verloren.
Oder nehmen wir die Situation, dass Spalten berechnet werden (z.B. kumulierte Werte)
oder abhängig vom Anwender ausgeblendet werden sollen (z.B. weil ihm die Berechtigung
fehlt).
Natürlich kann man diese Anforderungen auch in einem DataGrid abdecken - durch gezielte Manipulation des DataGrids und die Abbildung von Events des DataGrids auf Methodenaufrufe (wobei dann die Problematik der Datensynchronisierung zwischen Objekt und DataSet entsteht). Aber damit vermischt sich zwangsläufig Oberflächen- und Geschäftslogik.
Genügend Gründe also, sich des Themas anzunehmen - genügend Gründe aber auch, im Einzelfall kritisch zu hinterfragen, ob sich der Aufwand lohnt oder ob er zum Selbstzweck verkommt.
Für XML ist keine dem DataView/DataRowView (System.Data.DataView/System.Data.DataRowView) vergleichbare Infrastruktur aufgebaut. Führt man hier ein Databinding durch, etwa an eine von einem Aufruf an SelectNodes() gelieferte XmlNodeList (System.Xml.XmlNodeList), dann erhält man - nach dem in Teil 1 vorgestellten Schema - die Properties der einzelnen XmlNodes (System.Xml.XmlNode) - HasChildNodes, InnerText, etc. - kaum das, was man erreichen will:

Abb. 6: Databinding an ein XML-Dokument
Ergo muss das, was für DataSets durch die .NET Framework Class Library (FCL) bereitgestellt wird, nach den Anforderungen die man an ein Databinding an XML stellt, selbst implementiert werden.
Fangen wir mit dem an, was wir erreichen wollen (immer eine gute Herangehensweise, wenn man wieder verwendbaren Code schreiben will). Ich habe ein XML-Dokument verwendet, in dem eine Menüstruktur verwaltet wird. Es besteht aus Gruppen und Einträgen mit Name, Link und Beschreibung. Die Gruppen selbst haben ebenfalls Namen und können ineinander geschachtelt werden, bilden also eine rekursive Struktur. Hier ist ein verkürzter Ausschnitt:
<Catalog>
<LastChange>20.08.02</LastChange>
<Group ID="1" Name="XML">
<Description>Things related to basic XML</Description>
<Group ID="2" Name="W3C">
<Description>W3C standards</Description>
<Entry>
<Name>XML</Name>
<Link>www.w3.org</Link>
</Entry>
<Entry>
<Name>XSL</Name>
<Link>www.w3.org</Link>
</Entry>
</Group>
</Group>
<Group ID="3" Name="WebServices">
<Description>WebService resources</Description>
<Group ID="4" Name="Microsoft">
<Description>Links to and about Microsoft</Description>
<Entry>
<Name>Global XML Web Services Architecture</Name>
<Link>gotdotnet.com </Link>
<Description>Description of Microsoft's GXA</Description>
</Entry>
</Group>
<Group ID="5" Name="IBM">
<Description>IBM AlphaWorks</Description>
<Entry>
<Name>WebService insider, Part 1-10</Name>
<Link>http://www-106.ibm.com</Link>
<Description>advanced introduction to WS</Description>
</Entry>
</Group>
</Group>
</Catalog>
Das mag für die hier beschriebene Darstellung als flaches DataGrid nicht sehr sinnvoll erscheinen. Ich habe ganz einfach ein XML Dokument ausgesucht, das von einem DataSet nicht direkt verarbeiten werden kann und das ich mittels XPath-Abfragen sinnvoll umordnen und umstrukturieren kann. Der Grund für die Ablehnung durch das DataSet ist übrigens der gleiche, wie im obigen Beispiel, nur ist hier Group die abgewiesene Tabelle.
Nun wäre es schön, wenn der folgende - (noch) fiktive - Code innerhalb einer ASP.NET-Seite einfach das tun würde, was man erwartet:
private void Test()
{
XmlDocument xml= new XmlDocument();
xml.Load(Server.MapPath("test.xml"));
// Abfrage auf alle (!) Entry-Elemente
XmlDataView dv= new XmlDataView(xml, "//Entry");
// automatische Spaltenerzeugung:
dv.AutoAddElements= true;
dv.AutoAddAttribs= true;
dv.AutoAddSelf= true;
// Explizit zugefügte Spalten, ausgehend vom Entry-Knoten:
// das untergeordnete Element Name
dv.AddColumn("c_code");
// das Attribut Name der Gruppe zwei Ebenen höher
dv.AddColumn("Group ", "../../@Name");
// das Attribut Name der übergeordneten Gruppe
dv.AddColumn("Group", "../@Name");
// das untergeordnete Element Description
dv.AddColumn("Description", "Description");
grid.DataSource= dv;
}
Im Einzelnen läuft hier folgendes ab:
Leider ist der Code nicht übersetzbar, geschweige denn lauffähig. Eine Klasse XmlDataView - der Name wurde in Analogie zu DataView gewählt - existiert schlichtweg nicht.
Wie gesagt, das war die Zielstellung. Was ist notwendig um sie Wirklichkeit werden zu lassen?
Der gerade vorgestellte Code entstand in Analogie zur Anbindung an ein DataSet. Das XmlDocument (System.Xml.XmlDocument) dient als Datenquelle, XmlDataView entspricht DataTable (System.Data.DataTable) bzw. DataView. Damit ergibt sich als erste Aufgabe die Verwaltung der Daten als eine Ergebnismenge, eine Art Resultset. Die Liste ergibt sich im Grunde von selbst durch Aufrufen der Methode SelectNodes() aus dem XML-Dokument.
Leider können wir mit einer XmlNodeList nicht sehr viel anfangen. Zwar ist ein Databinding an diese Liste problemlos möglich, aber das Resultat wurde bereits eingangs als unbrauchbar verworfen. Hier wird es also notwendig die Zeilen durch eine eigene Klasse zu repräsentieren, die für das korrekte Erzeugen und Füllen der Spalten sorgt.
Dazu benötigt sie die Hilfe einer weiteren Klasse, die diese Aufgabe für eine einzelne Spalte übernimmt. Die Form dieser Klasse gibt die FCL vor. Sie muss von PropertyDescriptor abgeleitet werden.
Natürlich würde es für den Anfang reichen, wenn wir die Zeilenobjekte in einem fertigen Container, etwa einem ArrayList (System.Collections.ArrayList) Objekt verwalten würden; vergleichbar haben wir auch im Teil 1 angefangen. Aber es ist durchaus sinnvoll, von vorne herein eine eigene Container-Klasse vorzusehen. Zum einen, weil der obige Code uns bereits vor die Anforderung stellt, Spalten gezielt per AddColumn() anzulegen, zum anderen würden wir schnell auf das Problem der leeren Liste stoßen, für dessen Lösung wir die eigene Klasse unbedingt brauchen.
Tragen wir das eben gesagte etwas strukturierter und konkreter zusammen:
Ein konzeptionelles Problem sollte noch kurz angesprochen werden: DataSets oder DataTables haben eine feste Struktur, die sich aus dem Datenbank- oder XML Schema ergibt und die auch dann zur Verfügung steht, wenn die Tabellen keine Daten beinhalten. Zudem bleibt diese Struktur auch über mehrere Datensätze hinweg stabil.
Bei einer Liste von XML-Knoten die mit beliebigem XPath-Ausdruck aus einem XML-Dokument gesucht werden ist das im Allgemeinen nicht der Fall. Vielmehr ist hier ein buntes Sammelsurium aus Attributen und Elementen unterschiedlichster Inhaltsmodelle möglich. Welche Spalten sollten also erzeugt werden?
Für die folgenden Betrachtungen soll es reichen, den ersten Knoten der Liste zu analysieren und - je nach Einstellung der AutoAddXY-Properties - für seine direkten Unterelemente, Attribute oder den Knoten selbst je eine Spalte zu erzeugen.
Dazu ist vielleicht ein kritischer Hinweis angebracht: Dieser Ansatz ist ausreichend, um das Databinding zu betrachten - robust und für den produktiven Einsatz gerüstet ist er sicher nicht. Eine denkbare Möglichkeit wäre eine Vereinigungsmenge aus diesen Informationen über alle Knoten hinweg zu bilden. Vielleicht nicht sehr effizient, aber es trägt den unvorhersehbaren Variationen der in der Menge enthaltenen Knoten Rechnung. Eine andere Variante wäre, dem XmlDataView Hilfestellung zu geben. Man könnte ihm etwa ein XML-Schema mitgegeben, das zur Erzeugung der Spalten in irgendeiner Form herangezogen würde.
Wir wissen bereits, dass wir ITypedList implementieren müssen, wenn wir auch für leere Listen Spalteninformationen für die Titel-Zeile des DataGrids bereitstellen wollen. Wir laufen jedoch auch hier in die Falle, dass beim gewählten einfachen Ansatz zur Spaltenerzeugung keine feste Struktur vorhanden ist. Welche Spalten sollen also erzeugt werden, wenn nicht einmal ein Knoten der Ergebnismenge zur Analyse herangezogen werden kann? (Und wieder der Hinweis für einen evtl. weiteren Ausbau: Auch hier würde ein bereitgestelltes XML Schema helfen.)
Wir werden das Interface trotzdem implementieren, immerhin können wir zumindest die manuell zugefügten Spalten verwenden.
Wir wissen welche Klassen wir brauchen, welche Aufgaben sie haben und so weiter. Es ist Zeit, mit der eigentlichen Umsetzung zu beginnen.
XmlDataView verwaltet die Informationen über die Spalten. Man kann manuell Spalten zufügen und die AutoAddXY-Properties setzen, die die automatische Spaltenerzeugung steuern. Danach führt man das DataBinding durch, während dem das DataGrid nach Informationen über Spalten und Zeilen anfragt. Hier ist der Klassen-Rahmen von XmlDataView mit Datenmembern und Properties:
public class XmlDataView: IEnumerable, ITypedList
{
XmlDocument m_xml; // XML doc
string m_sQuery; // xpath query
ArrayList m_alData; // query result
ArrayList m_alProps; // columns
PropertyDescriptorCollection m_props; // columns translated
bool m_bAutoAddElements = false;
bool m_bAutoAddAttribs = false;
bool m_bAutoAddSelf = false;
public XmlDataView(XmlDocument xml, string sQuery)
{
m_xml= xml;
m_sQuery= sQuery;
m_alProps= new ArrayList();
}
public bool AutoAddElements
{
get { return m_bAutoAddElements; }
set { m_bAutoAddElements= value; }
}
public bool AutoAddAttribs
{
get { return m_bAutoAddAttribs; }
set { m_bAutoAddAttribs= value; }
}
public bool AutoAddSelf
{
get { return m_bAutoAddSelf; }
set { m_bAutoAddSelf= value; }
}
[...]
}
Der Aufbau der Ergebnismenge findet in einer eigenen Methode Query() statt. Query() führt per SelectNodes() die im Konstruktor an das XmlDataView übergebene XPath-Abfrage gegen das XML-Dokument durch. Das als XmlNodeList gelieferte Ergebnis wird jedoch nicht direkt gespeichert, vielmehr wird für jedes enthaltene XmlNode ein XmlDataRowView (analog DataRowView) erzeugt und in einem Container (einem ArrayList) abgelegt. Dieses Objekt erhält eine Referenz auf das ursprüngliche XmlNode um dieses zu einem späteren Zeitpunkt auswerten zu können.
Query() ist eine reine Arbeitsmethode. Sie kommt dann zum Einsatz, wenn das DataGrid nach einem Enumerator für die Datenzeilen fragt (XmlDataView implementiert IEnumerable). XmlDataView.GetEnumerator() ruft in diesem Fall zunächst Query() auf, danach wird einfach ein Enumerator des Ergebniss-Arrays zurückgeliefert. Hier sind die relevante Ergänzung des Codes von XmlDataView und das Grundgerüst zu XmlDataRowView:
public class XmlDataView: IEnumerable, ITypedList
{
[...]
protected void Query()
{
if (m_alData!=null) // Berechnung nur einmal
return;
XmlNodeList nl= m_xml.SelectNodes(m_sQuery);
// XMLNode => XmlDataRowView
m_alData= new ArrayList(nl.Count);
foreach( XmlNode node in nl)
m_alData.Add(new XmlDataRowView(this, node));
}
System.Collections.IEnumerator IEnumerable.GetEnumerator()
{
Query();
return m_alData.GetEnumerator();
}
[...]
}
public class XmlDataRowView: ICustomTypeDescriptor
{
XmlDataView m_view; // view that created this instance
XmlNode m_node; // node this instance represents
public XmlDataRowView(XmlDataView view, XmlNode node)
{
m_view= view;
m_node= node;
}
public XmlNode Node
{
get { return m_node; }
}
[...]
}
Damit stehen die Daten für die Zeilen in einem Container in Form von eigenen Objekten bereit.
Die Spalteninformationen kommen aus zwei Quellen. Zum einen sind da die im XmlDataView manuell eingefügten Spalten, zum zweiten die aus den XML-Daten dynamisch - gesteuert über die AutoAddXY-Properties - zu erzeugenden Spalten.
Zum manuellen Zufügen hat die Klasse XmlDataView eine Methode AddColumn(), die Spalteninformationen werden als Objekte vom Typ XmlDataViewCol in einem Container vom Typ ArrayList abgelegt. Als Information wird der Name der Spalte für die Überschrift benötigt, sowie ein XPath-Ausdruck. Dieser wird später zum Auslesen der Daten relativ zum Knoten der aktuellen Zeile verwendet werden.
Zur Sicherheit prüft AddColumn() zuvor, ob das DataGrid bereits Spalteninformationen angefordert hat. Hier die Ergänzung an XmlDataView und der Grundstock für XmlDataViewCol:
public class XmlDataView: IEnumerable, ITypedList
{
[...]
public void AddColumn(string sName)
{
AddColumn(sName, sName);
}
public void AddColumn(string sName, string sQuery)
{
if (m_props!=null)
throw new Exception("Columns fixed!!!");
m_alProps.Add(new XmlDataViewCol(sName, sQuery));
}
[...]
}
public class XmlDataViewCol: PropertyDescriptor
{
public string m_sName; // Name of column
public string m_sQuery; // xpath query to get value
public XmlDataViewCol(string Name )
: base(Name, null)
{
m_sName= m_sQuery= Name;
}
public XmlDataViewCol(string Name, string query)
: base(Name, null)
{
m_sName= Name;
m_sQuery= query;
}
[...]
}
Nun fragt das DataGrid aber gar nicht beim XmlDataView nach den Spalteninformationen (zumindest nicht, solange ITypedList noch nicht implementiert ist). Es fragt beim ersten Element der Liste nach, einem Objekt vom Typ XmlDataRowView.XmlDataRowView implementiert um diese Informationen zu liefern das Interface ICustomTypeDescriptor. Von den vielen Methoden, die ICustomTypeDescriptor mitbringt, ist lediglich GetProperties() interessant. Alle anderen Methoden delegieren ihre Arbeit einfach an TypeDescriptor (System.ComponentModel.TypeDescriptor), eine Hilfsklasse in der FCL.
Und da die manuell zugefügten Spalten ohnehin im übergeordneten XmlDataView verwaltet werden delegiert GetProperties() die Arbeit ebenfalls weiter und wird dadurch ebenfalls recht trivial. Nur zu diesem Zweck wurde dem XmlDataRowView die Referenz auf sein XmlDataView spendiert.
public class XmlDataRowView: ICustomTypeDescriptor
{
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{ return TypeDescriptor.GetAttributes(this, true); }
string ICustomTypeDescriptor.GetClassName()
{ return TypeDescriptor.GetClassName(this, true); }
[...]
public PropertyDescriptorCollection GetProperties()
{
return m_view.GetPropertiesImpl();
}
}
Die Methode GetPropertiesImpl() im XmlDataView ist ähnlich einfach, genau wie GetEnumerator() die Arbeit an Query() delegiert, ruft sie eine Arbeitsmethode BuildProps() auf und liefert das Ergebnis zurück.
Die Methode BuildProps() erledigt die eigentliche Arbeit und baut die Spalteninformationen auf. Zunächst prüft BuildProps(), ob es seine Arbeit überhaupt erledigen kann. Wenn weder Spalten manuell zugefügt wurden, noch Daten in der Ergebnismenge enthalten sind, dann ist jede Informationsgewinnung unmöglich und damit die weitere Bearbeitung überflüssig.
Sofern vorhanden holt sich BuildProps() den ersten Eintrag aus der Liste der XmlDataRowViews. Abhängig von den entsprechenden AutoAddXY Properties sammelt sie die Elemente und Attribute des zugehörigen XML-Knotens bzw. den Knoten selbst und legt jeweils eine Spalte an. Dazu nimmt sie die gleiche Methode AddColumn() in Anspruch, die auch für das manuelle Zufügen der Spalten verwendet wurde. Als Bezeichner wird der Name des Elementes oder Attributes verwendet, als XPath-Ausdruck dient ebenfalls der Name, bei Attributen mit vorangestelltem Klammeraffen.
BuildProps() hat noch eine letzte Aufgabe: Die FCL erwartet eine PropertyDescriptorCollection, wir haben aber nur ein Array von XmlDataViewCol-Objekten die von PropertyDescriptor abgeleitet sind. Daher wird die Liste kurzerhand manuell kopiert und erst dieses Ergebnis wird zur späteren Verwendung gesichert.
public class XmlDataView: IEnumerable, ITypedList
{
[...]
protected void BuildProps()
{
if (m_props!=null) // Berechnung nur einmal
return;
Query();
if ((m_alData.Count==0) && (m_alProps.Count==0))
return;
if (m_alData.Count>0)
{
XmlDataRowView row = (XmlDataRowView)m_alData[0];
XmlNode node= row.Node;
if (AutoAddSelf)
AddColumn(node.Name, "");
if (node is XmlElement)
{
if (AutoAddElements)
{
foreach (XmlNode elem in node.SelectNodes("*"))
AddColumn(elem.Name);
}
if (AutoAddAttribs)
{
foreach (XmlNode attr in node.SelectNodes("@*"))
AddColumn(attr.Name, "@"+attr.Name);
}
}
}
// =>PropertyDescriptorCollection
PropertyDescriptor[] props= new PropertyDescriptor[m_alProps.Count];
for( int i= 0; i<m_alProps.Count; ++i)
props[i]= (PropertyDescriptor)m_alProps[i];
m_props= new PropertyDescriptorCollection(props);
}
internal PropertyDescriptorCollection GetPropertiesImpl()
{
BuildProps();
return m_props;
}
[...]
}
Somit stehen nun auch die Informationen für den Aufbau der Spalten bereit. Und nachdem die Spalteninformationen ohnehin im XmlDataView berechnet werden, wird die Berücksichtigung einer leeren Liste nahezu trivial: XmlDataView muss lediglich ITypedList implementieren, wobei die relevante Methode GetItemProperties() das gleiche GetPropertiesImpl() aufrufen kann, das auch von den XmlDataRowViews verwendet wird.
public class XmlDataView: IEnumerable, ITypedList
{
[...]
System.ComponentModel.PropertyDescriptorCollection
ITypedList.GetItemProperties(
System.ComponentModel.PropertyDescriptor[] listAccessors)
{
return GetPropertiesImpl();
}
}
Damit stehen nun auch die Informationen zum Erzeugen der Spalten bereit. Was jetzt noch fehlt ist das eigentliche Füllen des DataGrids.
Zum Füllen des DataGrids wurde bisher nur gesagt, dass die Zeilenobjekte vom Typ XmlDataRowView den XML-Knoten halten, während die Spaltenobjekte vom Typ XmlDataViewCol den XPath-Ausdruck verwalten, der den Weg vom XML-Knoten zum darzustellenden Inhalt weist.
Die Klasse XmlDataViewCol ist von PropertyDescriptor abgeleitet, was ja schon ausgenutzt wurde, um die Spaltenüberschrift zu setzen. Die Klasse ist jedoch auch für das Bereitstellen der eigentlichen Inhalte zuständig. Beim Füllen des DataGrids werden alle Elemente des von XmlDataView.GetEnumerator() bereitgestellten Enumerators abgearbeitet.
Für jedes dieser Objekte - die ja alle vom Typ XmlDatRowView sind - wird für jede Spalte im zugehörigen XmlDataViewCol-Objekt die Methode GetValue() aufgerufen, als Parameter wird das Zeilen-Objekt übergeben. GetValue() kann also den als object übergebenen Parameter auf XmlDataRowView casten, den XML-Knoten auslesen, seinen eigenen XPath-Ausdruck darauf anwenden (bei leerem Ausdruck wird der Knoten selbst als Ergebnis interpretiert) und das Ergebnis als Text zurückzuliefern.
public class XmlDataViewCol: PropertyDescriptor
{
[...]
public override object GetValue(object component)
{
XmlDataRowView row = (XmlDataRowView)component;
XmlNode node = row.Node;
XmlNode result;
if (m_sQuery.Length==0) // Abfrage oder Selbstbezug?
result= node;
else
result= node.SelectSingleNode(m_sQuery);
return (result!=null) ? result.InnerXml : "{null}";
}
};
Ziel erreicht! Damit ist der Quelltext der als Anforderung diente übersetzbar und voll lauffähig.
Hier ist die Ausgabe unter Ausnutzung der automatisch generierten Spalten:

Abb. 7: Databinding an ein XmlDataView mit automatisch erzeugten Spalten
Hier die Ausgabe aus der Anforderung mit manuell zugefügten Spalten, man beachte die beiden gleichnamigen Spalten:

Abb. 8: Databinding an ein XmlDataView mit manuell zugefügten Spalten
Und hier die Ausgabe bei leerer Ergebnismenge. Sollten die AutoAddXY-Properties entsprechend gesetzt sein, können bei gefüllter Ergebnismenge noch Spalten hinzukommen.

Abb. 9: Databinding an ein XmlDataView mit manuell zugefügten Spalten und leerer
Ergebnismenge
Übrigens hätte man natürlich auch die Methode GetValue() an XmlDataView delegieren können, genau wie das mit der Gewinnung der Spalteninformationen geschah. Vorteil wäre, dass damit nahezu die gesamte Logik in einer zentralen Klasse konzentriert und nicht über diverse Klassen verteilt wäre. Das klingt im vorliegenden Fall vielleicht etwas akademisch; falls aber jemand diese Vorgehensweise auf eigene Objektstrukturen anwenden möchte, ist das sicher sinnvoll.
Databinding ist eine mächtige Sache, die auf den ersten Blick vielleicht in der Funktionalität am DataSet ausgerichtet zu sein scheint, aber über Interfaces genügend Eingriffsmöglichkeiten bietet. Pferdefuß ist, dass man dazu wissen muss, wo man wie und warum eingreifen muss. Leider ist die .NET-Framework-Dokumentation in erster Linie eine Referenz, Zusammenhänge werden in der Regel nicht erklärt. Zumindest für den behandelten Themenbereich hat Teil 1 diese Lücke hoffentlich geschlossen. Und mit Teil 2 wurde ein Databinding an XML realisiert, das als nicht-triviales Beispiel Hilfestellung für eigene Entwicklungen bieten kann.
Alexander Jung ist Software-Architekt und arbeitet als Managing Developer bei NEW LINE Software Development GmbH. Weitere Informationen finden sich unter http://www.alexander-jung.net/.
Kontakt: info alexander-jung.net |
top | Letzte Änderung: 27.08.2005 23:31:17 |