Visual Studio LightSwitch unter der Lupe

Seite 3: Bildschirme

Inhaltsverzeichnis

Der zweite Hauptast neben "Data Sources" im Solution Explorer ist "Screens". Der "Add New Screen"-Dialog bietet fünf Vorlagen (siehe Abbildung 6) und die Auswahl der Datenmenge(eine Menge von Entitäten oder eine Abfrage), die die Grundlage für den Bildschirm bilden soll.

Vorlagen für die Bildschirmaufteilung (Abb. 6)

Einen schnellen Erfolg bringt die Vorlage "Editable Grid Screen". Nach der Auswahl der Datenquelle (in Abbildung 6 die Entitätsmenge "PersonSet") erscheint eine hierarchische Ansicht des Bildschirmaufbaus (siehe Abbildung 7), die man anpassen kann.

Bearbeiten der Bildschirmgestaltung (Abb. 7)

Doch vor der ersten Anpassung sichert man sich ein Erfolgserlebnis durch einen Druck auf "F5" ("Start Debugging"). Es erscheint der Bildschirm "Personenliste" im Menü, der eine komplette Tabellenansicht der Personen mit Blättern, Filtern, Sortieren, Ändern, Hinzufügen und Löschen bietet. Beim Nachladen von Daten zeigt die Anwendung die aktuellen Datensätzen unscharf, und ein rotierender Kreis deutet dem Nutzer an, dass er warten muss. Warten muss der Nutzer bei der Beta 1 noch häufig, LightSwitch-Anwendungen zeigen sich nicht sehr performant. "Export to Excel" präsentiert die Datensätze in Excel, sofern es auf dem lokalen System installiert ist.

Die Personenpflegetabelle zur Laufzeit (Abb. 8)

Für das Ändern und Hinzufügen von Datensätzen würde man sich eine Detailansicht wünschen. Es bieten sich zwei weitere Bildschirme für "PersonSet" auf Basis der Vorlagen "New Data Screen" und "Details Screen" an. Der Bildschirm "NeuePerson" erscheint nach dem Anlegen auch im Baum. Fett geschriebene Bezeichnungen zeigen die Pflichtfelder an, rote Markierungen geben leer gelassene Pflichtfelder oder Verstöße gegen die in der Datenquelle hinterlegten Einschränkungen und den Überprüfungscode in der Validate()-Methode aus. Nach dem Speichern des neuen Eintrags wechselt die Ansicht automatisch zu "PersonenDetails". Dieses Umschaltverhalten ist in zwei Zeilen Code in NeuePerson_Saved() hinterlegt und dort änderbar.

Eingabe neuer Personen (Abb. 9)

"PersonenDetails" basiert auf der Vorlage "Details Screen". In dem Assistenten kann man nachlesen, dass sich die Bildschirme nicht direkt auf dem Hauptmenü aufrufen lassen, da die Grundlage hierfür eine parametrisierte Abfrage ist. Den Aufruf this.Application.ShowPersonenDetails(PersonenID) mit der Übergabe einer PersonenID könnte man zum Beispiel in die Personenliste (Abbildung 8) als zusätzlich Aktion "Detailansicht" einfügen. Der nach dem Erstellen des Button-Steuerelements im Screendesigner erforderliche Code sähe dazu wie folgt aus:

partial void Detailansicht_Execute()
{
if (this.PersonCollection.SelectedItem != null)
this.Application.ShowPersonenDetails(this.PersonCollection.
SelectedItem.PersonID);

}

Die neue Schaltfläche lässt sich wahlweise in die Befehlsleiste oberhalb der Tabelle oder in die Tabelle platzieren. Eine einzelne Zelle kann mehrere Button- und Link-Objekte besitzen.

Der Bildschirm-Designer bietet einige Anpassungsoptionen. Die Leiste auf der linken Seite zeigt die verfügbaren Aktionen. Die oberste ist die Abfrage selbst, für die man Eigenschaften wie die Seitengröße einstellen kann. Für die Aktionen "Close" und "Save" kann der Entwickler Programmcode hinterlegen, der bei Beginn und nach Ende der Aktion ausgeführt werden soll. Bei den Beginn-Ereignissen ist ein Abbruch möglich. Abbildung 10 zeigt mit "ExportHTML" eine vom Entwickler selbst definierte Aktion (mit "Add Button" in dem Ast "Command Bar").

Festlegen der Abfrageeigenschaften im Screendesigner (Abb. 10)

Für solche Schaltflächen gibt es zwei implementierbare Methoden: CanExecute() liefert zurück, ob die Aktion aktuell umsetzbar ist. Execute() führt die Aktion aus. Eine Implementierung für eine Export-Funktion zeigt das folgende Listing. Zu beachten ist, dass eine LightSwitch- genau wie eine Silverlight-Anwendung außerhalb des Browsers nicht auf alle Pfade zugreifen darf.

/// <summary>
/// Aktion "Export HTML"
/// </summary>
partial void ExportHTML_Execute()
{
string DateiName = System.IO.Path.Combine(Environment.GetFolderPath
(Environment.SpecialFolder.MyDocuments), "export.htm");
System.IO.StreamWriter sw = new StreamWriter(DateiName, true);
sw.WriteLine("<html><body><table>");
foreach (var p in this.PersonCollection)
{
sw.WriteLine("<tr><td>" + p.PersonID + "</td><td>"
+ p.Name + "</td><td>" + p.Geburtstag + "<7td></tr>");
}
sw.WriteLine("</table></body></html>");
sw.Close();

this.ShowMessageBox("Liste exportiert nach " + DateiName);
}

Bei allen Ausgaben in den selbst definierten Aktionen ist Vorsicht geboten, denn sie werden asynchron gestartet. Schon ein einfaches Dialogfeld läuft auf "Invalid cross-thread access", wenn man es nicht korrekt mit dem UI-Thread synchronisiert. Ein direkter Zugang zu den Steuerelementen der Benutzeroberfläche über die Methode FindControl() erfordert immer eine Synchronisierung der Threads. Für einfache Standarddialoge bietet die Basisklasse Microsoft.LightSwitch.Framework.Client.ScreenObject, von der alle Bildschirme abgeleitet sind, die Methoden ShowMessageBox() und ShowInputBox().

Auch die angezeigten Felder sind anpassbar. Zum einen kann man die Reihenfolge der Elemente per Drag[]& Drop verschieben. Zum anderen lässt sich das zur Darstellung verwendete Steuerelement auswählen. Als Drittes kann man neben dem Attribut der angezeigten Entität sogenannte lokale Attribute anlegen; sie sind dann per Programmcode zu befüllen, etwa in den Ereignissen Loaded() oder Saved(). Zum Beispiel könnte man ein weiteres Feld "Alter" definieren, dass anhand des Geburtsdatums zusätzlich das Alter einer Person anzeigt. In der Liste der verfügbaren Ereignisse vermisst man im ersten Moment eines, das ausgelöst wird, wenn sich der Inhalt eines Eingabefeldes ändert. Hier muss man etwas umdenken: Im obigen Fall würde man "Alter" als berechnetes Feld in der Entität anlegen und darauf in den Bildschirm aufnehmen. Bei jeder Änderung am Geburtstag erfolgt so automatisch die Neuberechnung von Alter. Alternativ gibt es auf der Ebene der Entität für jedes Attribut ein "Changed"-Ereignis.

Die Anpassung eines Bildschirms ist normalerweise mit vielen Wechseln zwischen Designer und laufendem Programm verbunden. Um das zu vermeiden, kann man während des Debuggings einen Bildschirm im laufenden Betrieb anpassen. Dazu dient die Schaltfläche "Customize Screen", die bei dem Vorgang oben rechts in der Ecke erscheint. Ein Klick darauf öffnet den "Customization Mode", in dem sich die Reihenfolge, die Steuerelemente und die Steuerelementeigenschaften beeinflussen lassen. Die Vorschau zeigt den aktuellen Stand. Alle hier vorgenommenen Änderungen sind sofort nach Beenden des Dialogs in der Anwendung sichtbar und bleiben auch nach dem Ende des Debuggings erhalten.

Anpassungen des Bildschirms während des Debuggings (Abb. 11)

Vergeblich sucht man in der Bildschirmkonfiguration nach Einstellungen wie Farbe, Schriftart und Schriftgröße. Alle gestalterischen Eigenschaften steuert LightSwitch zentral über das in den Projekteigenschaften ausgewählte "Theme". Derzeit liefert Microsoft nur eines mit ("LightSwitch Blue Theme"). In Zukunft soll man weitere Layoutvorhaben über den aus Visual Studio 2010 bekannten Extension Manager aus dem Internet nachladen können. Codezentriert kann man aber die einzelnen Gestaltungsattribute der Steuerelemente weiterhin annavigieren, wenn auch etwas komplizierter, als man es bisher kennt, was man als eine Richtungsweisung verstehen sollte.

Einfluss über den Standort eines Bildschirms in der Menüstruktur der Anwendung hat der Entwickler ebenfalls in den Projekteigenschaften, und zwar in der Registerkarte "Screen Navigation". Die Navigationsstruktur ist technisch auf eine Ebene begrenzt, das heißt, eine beliebig tiefe Baumstruktur ist nicht möglich.

Ein direkter Zugriff auf den XAML-Code des Bildschirms ist in LightSwitch nicht vorgesehen. Entwickler können in Visual Studio 2010 selbst Silverlight-Steuerelemente entwickeln, die ebenfalls in LightSwitch verwendbar sind oder sogar einen ganzen Bildschirm ersetzen. Eine Dokumentation dazu ist aber aktuell noch nicht verfügbar, allerdings zeigen ein Video auf Channel 9 und ein Blog-Eintrag die Grundzüge.

Eine geeignete Vorlage für die Darstellung verbundener Entitäten ist "List and Details", wobei "PassagierSet" als "Screen Data" und "FlugPassagierSet" als "Additional Data to include" zu wählen sind. Das Ergebnis (siehe Abbildung 12) ist noch nicht optimal, denn es zeigt als Repräsentation für den Flug immer nur den Abflugort an und die Passagiere kann man nur über die PersonenID zuordnen.

Master-Detail-Ansicht (Abb. 12)

Um die Anzeige der Flüge zu ändern, erstellt man in den "Data Sources" in der Entität "Flug" ein neues Attribut "FlugSummary" vom Typ "String". Für das Attribut ist automatisch vorgegeben, dass sich "Required" nicht aktivieren lässt und "IsComputed" gesetzt ist. Nach dem Klick auf "Edit Method" vervollständigt man den erscheinenden Methodenrumpf wie folgt:

partial void FlugSummary_Compute(ref string result)
{
result = this.Abflugort + " -> " + this.Zielort +
" (Flug #" + this.FlugNr + ")";
}

Dann legt man in den Eigenschaften der Entität "Flug" noch fest, dass "FlugSummary" nun "Summary Properties" ist (Abbildung 13). Fortan zeigt die Anwendung für Flüge immer die hinterlegte Kombination aus Abflugort, Zielort und Flugnummer an.

Erstellen eines berechneten Attributs als "Summary Property" (Abb. 13)