Dieser Blog beschreibt, wie man mit einer Silverlight-Anwendung ein BPOS-ListItem updaten kann, das eventuell leere Felder hat. Das Grundproblem besteht darin, dass man zuerst das Item laden muss, bevor es aktualisiert werden kann. Aus verständlichen Performance-Gründen sendet der Web Service aber nur Felder mit Inhalt.
Diese werden auf Attribute gemappt. Wenn ein Attribut fehlt, weil es im Item keinen Inhalt hat, dann laufen wir auf einen Fehler wenn wir auf das Attribut zugreifen um es in unsere Eingabemaske zu schreiben.
Zwei Lösungsansätze – Attribute hinzufügen oder vor jedem Zugriff testen
Attribute hinzufügen
In der beschriebenen BPOS-Lösung wurde eine interaktive Eingabemaske erstellt, die sowohl zum Anlegen als auch zum Aktualisieren eines Items verwendet wird.
Die zugrundeliegende Tabelle sieht in diesem Beispiel so aus:
Dabei wird das zu aktualisierende Item über den Namen gesucht, der in einem AutoComplete-Feld eingeben wird.
Ich habe dabei folgende Abfrage entwickelt, die eine Helpermethode zum erzeugen der Query verwendet.Die Enumeration ClubListen dient dazu, die verschiedenen asynchronen Requests zu identifizieren.
XElement query = XDocument.Parse(this.makeCamelID(this.AutoNamen.Text)).Element("Query");
this.flagListe = ClubListen.MITGLIED_EINFUEGEN;
proxy.GetListItemsAsync(ListenGUID.Mitglieder, null, query, null, null, null, null);
Die Methode wird beim Klick auf den Button Einfügen ausgelöst.
Die registrierte Callback-Methode sieht dann so aus:
void proxy_GetListItemsCompleted(object sender, GetListItemsCompletedEventArgs e)
{
….. // Code ausgelassenif (flagListe == ClubListen.MITGLIED_EINFUEGEN)
{
this.populateMaske(e);}
…… // Code ausgelassen
}
Ich rufe die Helpermethode populateMaske(e) auf, der als Parameter das Ergebnis des asynchronen Request übergeben wird. Und in dieser Methode wird dann das eingangs beschriebene Problem gelöst.
Die Methode ist relativ lang. Deshalb wird sie hier in kleinen Modulen beschrieben.
In einem ersten Schritt sorge ich dafür, dass fehlende Attribute erzeugt und mit einem Standardwert belegt werden. Dazu brauche ich einen String, der alle Attribute, die ich erwarten muss, enthält. Dieser String mappt in gewisser Weise die Eingabemaske.
String suchString = "ows_Title;ows_FirstName;ows_WorkAddress;ows_WorkZip;ows_WorkCity;ows_HomePhone;";
suchString += "ows_Email;ows_Geburtstag;ows_Abteilung;ows_Posten;ows_Mitglied_seit;ows_ID";
Als nächste erzeuge ich ein XElement, welches das für die Maske relevante Element aus dem XML des asynchronen Requests extrahiert. Dazu muss man natürlich den Aufbau des Response kennen. Dieser wird aber noch an anderer Stelle in einem Blogbeitrag beschrieben werden.
XElement element = e.Result.Elements().First().Elements().First();
In diesem Element finde ich aber nur die Attribute der Felder des Items, die nicht leer sind.
Deshalb müssen wir nun schauen, welche Attribute fehlen.
IEnumerable<XAttribute> attribute = element.Attributes();
String[] myAttribute = new String[attribute.Count()];int i = 0;
foreach (XAttribute attribut in attribute)
{
myAttribute[i] = attribut.Name.ToString();
i++;
}foreach (String s in suchString.Split(‘;’))
{
if (!myAttribute.Contains(s))
{
XAttribute x = new XAttribute(s, "");
element.Add(x);
}
}
Als erstes erzeugen ich eine iterierbare Attribut-Collection. Deren Anzahl dient zur dynamischen Erzeugen eines String-Arrays, in das ich den Namen der Attribute schreiben.
int i = 0;
foreach (XAttribute attribut in attribute)
{
myAttribute[i] = attribut.Name.ToString();
i++;
}
Jetzt weis ich, welche Attribute, sprich Felder, übertragen wurden.
Im nächsten Schritt lege ich alle Attribute an, die nicht übertragen wurden, weil die Felder im SharePoint-Item leer waren.
foreach (String s in suchString.Split(‘;’))
{
if (!myAttribute.Contains(s))
{
XAttribute x = new XAttribute(s, "");
element.Add(x);
}
}
Finde ich das Attribut, genauer seinen Namen nicht, weil es nicht im String enthalten ist, dann erzeuge ich das Attribut und füge es dem XElement zu.
Jetzt kann ich alle meine Maskenfelder füllen. Sollten zukünftig weitere Felder hinzukommen, muss ich lediglich den Suchstring erweitern.
Vor jedem Zugriff Testen, ob das Attribute vorhanden ist
Bei diesem Ansatz habe ich ein Array mit allen möglichen Attributen erstellt, die ich in die Eingabemaske schreiben möchten. Ein Ausschnitt des Arrays sieht dann so aus:
this.mAttribute[1] = "ows_FirstName";
this.mAttribute[2] = "ows_Title";
this.mAttribute[3] = "ows_Strasse";
this.mAttribute[4] = "ows_WorkZip";
this.mAttribute[5] = "ows_WorkCity";
Beim Befüllen der Maske überprüfe ich vor jedem Zugriff, ob es das Attribut gibt. Wenn ja, schreibe ich seinen Inhalt, Value, in das entsprechende Eingabefeld.
if (myAttribute.Contains(mAttribute[1])) this.txtName.Text = element.Attribute(mAttribute[1]).Value;
if (myAttribute.Contains(mAttribute[2])) this.txtNachname.Text = element.Attribute(mAttribute[2]).Value;
if (myAttribute.Contains(mAttribute[3])) this.txtStrasse.Text = element.Attribute(mAttribute[3]).Value;
if (myAttribute.Contains(mAttribute[4])) this.txtPLZ.Text = element.Attribute(mAttribute[4]).Value;
if (myAttribute.Contains(mAttribute[5])) this.txtOrt.Text = element.Attribute(mAttribute[5]).Value;
Bei entsprechendem Aufbau der Eingabemaske kann mit wenig Aufwand die Eingabemaske um weiteren Feldern erweitert werden. Dazu muss dann lediglich das Array erweitert werden.
