Fachpraktikum Graphische Benutzungsoberflächen Aufgabe 3: TODO-Liste mit WPF
←
→
Transkription von Seiteninhalten
Wenn Ihr Browser die Seite nicht korrekt rendert, bitte, lesen Sie den Inhalt der Seite unten
Universität Stuttgart Institut für Visualisierung und Interaktive Systeme Fachpraktikum Graphische Benutzungsoberflächen Aufgabe 3: TODO-Liste mit WPF Christoph Müller, Guido Reina Bearbeitungszeit: 3 Wochen In dieser Aufgabe werden Sie eine einfache TO- C# ist syntaktisch stark an C und C++ ange- DO-Liste implementieren. Die Extensible App- lehnt. Der großen Schar von C/C++- lication Markup Language (XAML) und die Programmierern soll dadurch wohl der Um- Windows Presentation Foundation (WPF) sol- stieg erleichtert werden. Es gibt jedoch einige len als Beispiel für die deklarative Erstellung kleine Unterschiede, wie zum Beispiel die einer Benutzungsoberfläche mit Hilfe einer Tatsache, dass am Ende einer Klasse kein Se- Markup-Sprache dienen. Die dahinterstehende mikolon gesetzt werden muss. Die Struktur Programmlogik soll in C# unter Verwendung des Quelltexts von C#-Programmen unter- des .NET-Frameworks realisiert werden. Wich- scheidet sich weiterhin darin, dass es keine tige Lernziele sind unter anderem Trennung von Klassen-Deklarationen und Erstellen von Oberflächen mit XAML Definitionen gibt, alle Methoden sind sozusa- gen „inline“. Ereignisbehandlung in XAML und im „code behind“ Die folgenden Abschnitte sollen auf Eigenhei- ten von C# hinweisen, die bei der Lösung die- C#-Events, Delegates und Reflection ser Aufgabe relevant sind. Weitergehende Bindung von Widgets an Datenquellen Informationen zur Sprache C# finden sich in Internationalisierung den Standards ECMA-334 und ISO/IEC 23270:2006, sowie in der MSDN Library†. C# und .NET Objekt-Orientierung Die Sprache C# wurde als Bestandteil der .NET-Plattform* von Microsoft entworfen. Sie C# ist vollständig Objekt-orientiert, das heißt verwendet daher, wie alle .NET-Sprachen, die Funktionen, wie sie in C++ noch erlaubt sind, Common Language Runtime (CLR), eine mit sind in C# nicht mehr möglich. Auch ein ein- der Java-VM vergleichbare virtuelle Maschine, faches „Hello World“-Programm erfordert welche den vom C#-Compiler erzeugten, daher mindestens eine Klasse und sieht einem CPU-unabhängigen Zwischencode (Common Java-Programm recht ähnlich: Intermediate Language, CIL) vor der tatsächli- using System; chen Ausführung in Maschinencode übersetzt. class Hello { Der Zwischencode, der aus den .NET- [STAThread] Sprachen C#, Visual Basic .NET, J# und Mana- static void Main(string[] arg) { ged C++ generiert wird, ist austauschbar, so Console.WriteLine("Hello, " dass es im Prinzip keine Relevanz hat, welche + "World."); Sprache man verwendet. } Zum .NET-Framework gehört außerdem eine } große Klassenbibliothek, die von Basisfunk- Der Eintrittspunkt einer Anwendung ist im- tionalität wie Strings über Collections bis zu mer die statische Methode Main, welche der Betriebssystemaufrufen fast alle notwendigen main- respektive WinMain-Funktion in C ent- Grundlagen zur schnellen Implementierung spricht. eines neuen Programms anbietet. Die Biblio- Oberhalb von Klassen existiert in der Klassen- thek ist ebenfalls mit allen .NET-Sprachen auf bibliothek von .NET eine strenge Hierarchie ähnliche Weise verwendbar. † http://msdn2.microsoft.com/en- * http://www.microsoft.com/net/ us/vcsharp/aa336809.aspx 1
von Namespaces. Diese können mit Hilfe des public event MyHandler Schlüsselworts using importiert werden. Die MyEvent; Anweisung using System; im oben stehen- private void raiseMyEvent() { den Programmfragment bewirkt, dass die // Calls all registered Klasse Console direkt verwendet werden // listener callbacks. kann und nicht über System.Console refe- MyHandler h = this.MyEvent; renziert werden muss. Im Programmskelett if (h != null) { für diese Aufgabe sind die erforderlichen Na- h(); mespaces in den entsprechenden Dateien } bereits eingebunden. } } Garbage Collector Andere Objekte können sich nun mit Hilfe des +=-Operators als Konsumenten des Events Wie Java besitzt C# einen Garbage Collector, MyEvent registieren oder mit -= die Benach- der einmal reservierten Speicher wieder frei- richtigungen wieder abbestellen. Auch das soll gibt, sobald er nicht mehr benötigt wird. ein Programmfragment verdeutlichen: Delegates und Events public class MyListener { public void OnMyEvent() { Delegates übertragen das Konzept von Funk- Console.WriteLine("MyEvent " tionszeigern in die streng typisierte Welt von + "was raised."); C#. Ein Delegate-Typ referenziert eine Me- } thode mit einem festgelegten Rückgabewert public void Register(MyClass und einer festgelegten formalen Parameterlis- myClass) { te. Die Deklaration myClass.MyEvent delegate int ConvertFunc(float f); += this.OnMyEvent; } hat somit eine ähnliche Semantik wie folgen- public void UnRegister(MyClass de Deklaration in C/C++: myClass) { typedef int (* ConvertFunc)(float); myClass.MyEvent Im Gegensatz zu Funktionszeigern in C++ -= this.OnMyEvent; } können Delegates auch nicht-statische Me- } thoden einer Klasse referenzieren. Eng verbunden mit den Delegates ist das Kon- zept der Events in C#. Ein Event bietet einer Properties Klasse einen Weg, andere Klassen über inter- Eigenschaftsfelder (englisch Properties) kap- essante Ereignisse zu informieren. Gerade bei seln die Überprüfungslogik beim Zugriff auf der Programmierung graphischer Benut- private Klassenvariablen. Diese Elemente ei- zungsoberflächen findet dieses Konzept häu- ner Klasse bedürfen der Implementierung fig Anwendung, zum Beispiel bei einem But- zweier vordefinierter Methoden (set und ton, der darüber informiert, wenn er geklickt get) und ermöglichen dann den transparen- wurde. ten schreibenden und lesenden Zugriff auf das Eigenschaftsfeld. Dadurch ist der Zugriff so Im Gegensatz zu Java, welches die Implemen- bequem wie bei öffentlichen Variablen, aber tierung des Observer Patterns durch den Prog- kann dennoch defensiv implementiert wer- rammierer erfordert, ist dieser Mechanismus den. bei C# in die Sprache integriert. Dadurch ent- fällt die explizite Verwaltung der Observer- private int myAttribute; Liste. Für einen Event sind also erstens ein public int MyAttribute { Delegate, welches die Signatur der aufzuru- get { fenden Callback-Methode festlegt, und die return this.myAttribute; Event-Deklaration selbst erforderlich. Das } folgende Programmfragment soll dies verdeut- set { lichen: if (isConsistent(value)) { this.myAttribute public delegate void MyHandler(); = value; public class MyClass { } else { 2
throw new und t2 im folgenden Beispiel beinhalten also ArgumentException(); beide die Typinformationen von string: } } string myString = "Meins!"; } Type t1 = myString.GetType(); Type t2 = typeof(string); In Kombination mit der Reflexion (s. u.) spie- Mit Hilfe des is-Operators kann festgestellt len Eigenschaftsfelder eine wichtige Rolle für werden, ob ein Objekt kompatibel zu einem die Datenbindung und die Serialisierung. Typ ist, also sicher in diesen Typ umgewandelt werden kann. Der Ausdruck Attribute bool b = (myString is string); Mit Hilfe von Attributen erlauben C# und alle wird also in unserem Beispiel zu true ausge- anderen .NET-Sprachen, Metadaten in den wertet. Quelltext zu integrieren. Das Konzept von Attributen reicht sogar so weit, dass beliebige Der as-Operator wiederum ist ein spezieller (von System.Attribute abgeleitete) benut- Typumwandlungsoperator, der im Gegensatz zerdefinierte Attribute verwendet werden zum gewöhnlichen Cast-Operator keine Ex- können. Attribute werden in eckigen Klam- ception wirft, wenn die Umwandlung fehl- mern vor einer Klassen-, Methoden- oder At- schlägt, sondern null zurückgibt. Während tributdeklaration angebracht. Das Attribut also Window w = (Window) myString; [Obsolete("Discontinued.")] private void SomeMethod() {...} eine InvalidCastException wirft, wird Window w = myString as Window; erzeugt zum Beispiel eine Compiler-Warnung, wenn SomeMethod verwendet wird, und mit einfach zu null ausgewertet. Damit ist der [XmlIgnore] kann ein Eigenschaftsfeld von letztgenannte Ausdruck äquivalent zu der XML-Serialisierung ausgeschlossen wer- try { den. Die MSDN Library enthält alle Details zu w = (Window) myString; Attributen*. } catch (InvalidCastException) { w = null; Reflexion } Unter Reflexion (englisch Reflection) versteht Die Windows Presentation Foundation ver- man den Umstand, dass ein Programm Infor- wendet intern häufig die Reflexion, um die mationen über seine eigene Struktur erlangen Verbindungen zwischen dem Markup, der das kann. Während C++ mit dem typeid- Aussehen der Benutzungsoberfläche definiert, Operator kaum mehr als den Namen einer und dem Quelltext, der das Verhalten festlegt, Klasse zur Verfügung stellt, was nur ansatz- herzustellen (ANDERSEN, 2007). So wird auch weise in Richtung Reflexion geht, besitzt C# die Datenbindung zwischen den Objekten, die ein mächtiges Reflection-API, das zur Laufzeit einen TODO-Listen-Eintrag repräsentieren, zum Beispiel die Enumeration von Feldern und deren Darstellung darauf beruhen, dass und Methoden, den Zugriff auf deren Sich- die darzustellenden Eigenschaften eines Ein- tbarkeitsattribute, den Zugriff auf die oben trags über das Reflection-API aufzählbar sind. erwähnten Attribute und den Aufruf von Auch die Speicherung der TODO-Listen in Konstruktoren und Methoden erlaubt. XML-Dateien wird deshalb nur erfordern, dass Die Reflexion erfolgt in C# über Objekte vom die zu speichernden Attribute als Properties Typ Type. Jedes Objekt in C# besitzt eine Me- sichtbar sind. Alles andere übernimmt das thode GetType(), die dieses Type-Objekt .NET-Framework mit Hilfe des Reflection-API. zurückgibt. Darüber hinaus kann das Type- Objekt einer Klasse mit Hilfe des typeof- WPF Operators beschafft werden. Die Variablen t1 Die Windows Presentation Foundation† ist eine der markantesten Neuerungen in der Version 3.0 des .NET-Framework. Sie ist eine * http://msdn2.microsoft.com/en- † us/library/xtwkdas5(VS.80).aspx http://www.microsoft.com/net/wpf.aspx 3
neue Bibliothek zur Erstellung von Windows- Darüber hinaus definiert XAML sogenannte Benutzungsoberflächen. Im Gegensatz zu den Markup Extensions, die in geschweiften althergebrachten Windows Forms, die auf den Klammern stehen. Zahlreiche vordefinierte nativen Windows-GUI-Komponenten beru- Extensions stammen aus dem XAML-XML- hen, basiert die WPF auf DirectX. Als Vektor- Namespace†, der meist im Wurzelelement Graphiken sind WPF-Oberflächen im Prinzip einer XAML-Datei mit dem Alias „x“ einge- frei skalierbar. Die Verwendung von DirectX bunden wird. Die folgende Markup Extension als Basis hat außerdem auch den Weg zu einer macht zum Beispiel einen als statische Variab- vollen Integration verschiedener Medientypen le im CLR-Code deklarierten Brush in XAML von Dokumenten über Audiodaten bis zu verfügbar: Videos und 3D-Modellen in ein einziges Prog- {x:Static SystemColors.DesktopBrush} rammiermodell geebnet. Ein wichtiges Kriterium beim Entwurf der Für die spätere Lokalisierung von statischen WPF war die Möglichkeit einer strikten Tren- Zeichenketten der Benutzungsoberfläche wer- nung von Design von Verhalten. Diese wird den wir darüber hinaus das Attribut x:Uid realisiert durch die deklarative Festlegung der verwenden, über welches jedem Tag ein ein- Benutzungsoberfläche in der XML-Sprache deutiger Bezeichner zugewiesen werden kann. XAML und die imperative Implementierung Im WPF-XML-Namespace‡ – dieser wird in des Verhaltens im „code behind“, beispiels- der Regel als Standard-Namespace verwendet weise in C#. und hat daher kein Namespace-Präfix – wer- den weitere fünf Markup Extensions definiert, XAML von denen insbesondere StaticResource und Binding für dieses Aufgabenblatt von Die Extensible Application Markup Language* Relevanz sind. Mit StaticResource kann auf ist eine XML-basierte Instantiierungssprache Ressourcen, die in der Resource-Property für CLR-Objekte, das heißt sie ermöglicht es, eines XAML-Elements definiert sind, zugegrif- Instanzen von CLR-Objekten „durch Auf- fen werden. Das folgende Beispiel soll dies schreiben“ zu erzeugen. Die statische Mäch- illustrieren: tigkeit ist prinzipiell mit der des dahinterste- henden Codes identisch, da es eine eindeutige Abbildung von XML-Tags auf CLR-Typen und von XML-Attributen auf CLR-Eigenschaften 0:0:0.1 und Events gibt: // C# [...] MyObject o = new MyObject(); Es wird hier eine innerhalb von sichtbare Konstante als Ressource deklariert, der mit der Markup Extension x:Key der Na- Die beiden obenstehenden Programmfrag- me „D1“ zugewiesen wird, und die dann später mente erfüllen exakt den gleichen Zweck, als Dauer einer Animation Verwendung fin- einmal in C# und einmal in XAML. Die Ver- det. wendung von Attributen oder Kindelementen für Eigenschaftsfelder oder Events ist dabei in XAML flexibel. Die folgende Zeile ist zu den Die TODO-Liste obenstehenden äquivalent: In dieser Aufgabe soll mit den oben beschrie- benen Technologien eine TODO-Liste erstellt werden, die in vier Quadranten unterteilt ist. 42 Diese bilden ein Koordinatensystem aus † http://schemas.microsoft.com/winfx/2006/ xaml * ‡ http://msdn.microsoft.com/en- http://schemas.microsoft.com/winfx/2006/ us/library/ms747122.aspx xaml/presentation 4
„Dringlichkeit“ auf der Abszisse und „Wich- TaskItemList.cs: Die hier implemen- tigkeit“ auf der Ordinate. Der positive Gra- tierte Klasse TaskItemList stellt die dient der beiden Werte wird durch animierte syntaktische Basis für das Datenmodell Vektorgraphik-Pfeile angezeigt (Abb. 1). für je eine der Quadrantenlisten dar. Window.xaml: Diese Datei beinhaltet den Markup des Hauptfensters. Window.xaml.cs: Diese Datei enthält den „code behind“ von Window.xaml. Mehrere Methoden zur Ereignisbehand- lung und eine Hilfsfunktion sind hier bereits implementiert. Eine ähnliche Solution erstellt auch der Pro- jekt-Assistent für neue WPF-Anwendungen. Das Hauptfenster Um das Hauptfenster mit Inhalt zu füllen, beginnen Sie zunächst mit einem DockPanel. Abb. 1 Screenshot der Musterlösung Damit können Sie Elemente an den Rändern des Vaterelements, in diesem Fall des Fens- Jeder Quadrant ist eine Liste, und die Zugehö- ters, anordnen. Verwenden Sie das im XAML- rigkeit zu dieser Liste legt implizit die Dring- Code bereits vorgegebene DockPanel, um lichkeit und Wichtigkeit eines Elements fest. eine Menüleiste und eine Toolbar im Fenster Neben Dringlichkeit und Wichtigkeit besitzen oben zu platzieren. die Elemente einen Namen, eine ausführliche Beschreibung sowie ein Fälligkeitsdatum. Ist Menüleiste und Toolbar eine Aufgabe erledigt, kann ein entsprechen- Fügen Sie zwei Menüs in die Menüleiste ein, des Flag gesetzt werden. Überfällige Aufgaben das Menü „Datei“ mit drei Einträgen zum Öff- werden durch eine Animation und durch die Farbgebung hervorgehoben, erledigte Aufga- nen einer Datei, zum Speichern und zum Be- enden der Anwendung und das Menü „Bear- ben grau und durchgestrichen dargestellt. beiten“ mit nur einem Menüpunkt „Löschen“. Es können Aufgaben zu allen Listen hinzuge- Bei den Einträgen im Menü „Datei“ setzen Sie fügt und aus allen Listen gelöscht werden. Per als Kommando jeweils eines der vordefinier- Drag&Drop können die Aufgaben zwischen den Listen verschoben werden. Dadurch än- ten ApplicationCommands. Binden Sie diese auch an die folgenden Shortcuts: dern sich implizit die Dringlichkeit und die Wichtigkeit des verschobenen Eintrages. Strg+O für „Öffnen“ Klickt der Benutzer auf eine der Aufgaben, so Strg+S für „Speichern“ wird an der Stelle des Listeneintrags ein Edi- Strg+E für „Beenden“ tor-Formular angezeigt, über das der Eintrag geändert werden kann. Darüber hinaus be- Implementieren Sie in „Window.xaml.cs“ Me- steht die Möglichkeit, alle Listen in eine XML- thoden zur Ereignisbehandlung für die Kom- Datei zu speichern und wieder daraus zu la- mandos. Die Methode onCloseCmdExecuted den. zum Beenden der Anwendung kann hier als Beispiel dienen. Für jedes der beiden Menüs erstellen Sie da- Das Programmskelett nach eine eigene Toolbar. Verwenden Sie die Das Programmskelett für diese Aufgabe steht im Programmskelett mitgelieferten Icons in Form einer Visual-Studio-Solution zur Ver- „open.ico“, „save.ico“, „exit.ico“ und „dele- fügung. Besonders erwähnenswert sind dabei te.ico“ für die Einträge und setzen Sie sinnvol- folgende Dateien: le Tooltips. Verwenden Sie für die Einträge in TaskItem.cs: In dieser Datei wird die der Toolbar dieselben Kommandos wie in den nahezu vollständige Klasse TaskItem Menüs. mit allen erforderlichen Attributen im- plementiert. 5
Der Client-Bereich zum enthaltenen Element weitergereicht, in der anschließenden Bubbling-Phase genau Als nächstes sollten Sie die Achsen für die umgekehrt (Abb. 3). An jeder Stelle im Weg Beschriftung der Quadranten einfügen. Den durch den Visual Tree kann ein Ereignis kon- Farbverlauf im Hintergrund erstellen Sie am sumiert werden, indem seine Handled- einfachsten mit einem LinearGradient- Eigenschaft auf true gesetzt wird. Dadurch Brush, die beiden Pfeile durch einen Polygon- wird die weitere Propagation dieses Ereignis- zug. ses abgebrochen. Das Standardverhalten eines Die vier Quadranten realisieren Sie mit einem Controls sollte durch Ereignisbehandlung in Grid, in das Sie die vier ListBoxes einfügen. der Bubbling-Phase realisiert werden. Die Vergessen Sie auch nicht die GridSplitter, meisten vordefinierten Ereignisse existieren mit denen die Größe der Quadranten geän- sowohl als Bubbling-Variante, als auch mit dert werden kann. Um die Listen zu testen, dem Präfix „Preview“ als Tunneling-Variante. können Sie einfach beliebig viele TextBlocks Wenn Sie das Standardverhalten eines Cont- als Kindknoten der Liste einfügen: rols überschreiben wollen, müssen Sie die Preview-Events verwenden. Element 1 Element 2 ListBox Tunnel Bubble Für die endgültige Darstellung sind komplexe- re Listenelemente notwendig, die ihren Inhalt aus den TaskItem-Instanzen beziehen. WPF TextBlock TextBlock erlaubt eine beliebige Verschachtelung von UI-Elementen, weshalb ein Listenelement beispielsweise auch aus einem Grid oder aus Abb. 3 Ereignis-Propagation durch Tunnel- weiteren ListBoxen bestehen kann. ing und Bubbling Der Visual Tree Styles und Templates Die verschachtelten Controls werden prog- Um das Erscheinungsbild der Listeneinträge rammatisch im sogenannten Visual Tree ab- zu beeinflussen, ohne jedes einzelne Element gebildet, der der aus der Grundlagenvorlesung explizit behandeln zu müssen, können soge- bekannten Window-Hierarchie entspricht. nannte Styles und Templates eingesetzt wer- den. Diese werden als Ressourcen, zum Bei- ListBox spiel im Window-Element, definiert. Der fol- gende Stil wird auf alle Buttons innerhalb des Window angewandt und setzt den Rand auf den Wert „5“: TextBlock TextBlock Der Visual Tree der obenstehenden ListBox sieht beispielsweise aus wie in Abb. 2. Er kann mit Hilfe der Klasse VisualTreeHelper* tra- versiert werden, um zum Beispiel den Vater- knoten eines Controls zu ermitteln. Stile in XAML beschränken sich jedoch nicht, Die Verarbeitung von Ereignissen in WPF wie dies zum Beispiel bei CSS der Fall ist, auf erfolgt entlang des Visual Tree in zwei Phasen: die statische Beschreibung des Aussehens von In der zuerst stattfindenden Tunneling-Phase Elementen, sondern können auch sogenannte werden die Ereignisse vom umschließenden Trigger beinhalten, die den Stil abhängig von Ereignissen oder dem Wert anderer Attribute beeinflussen. Der folgende Trigger ändert zum * http://msdn.microsoft.com/en- Beispiel die Vordergrundfarbe eines Elements, us/library/system.windows.media.visualtreehelp wenn die Maus über es bewegt wird: er(VS.85).aspx 6
Prinzipiell kann in WPF jedes Attribut über ein Data Binding befüllt werden. Auch lokale les und Templates, werden von WPF durch verwenden, müssen diese das Interface INo- tifyPropertyChanged implementieren. Über dieses Interface werden alle Änderun- gen, die an einem Objekt vorgenommen wer- Templates gehen einen Schritt weiter und den, durch ein Ereignis bekanntgegeben. Die sind im Prinzip mit dem Überschreiben der Oberfläche besitzt dann die Möglichkeit, ihre Zeichenmethode eines Widgets oder dem Darstellung nach jeder Änderung des Objekts Behandeln der WM_PAINT-Nachricht ver- zu aktualisieren. Collections, also Listen, Ar- gleichbar. Durch ein ControlTemplate kann rays etc., müssen darüber hinaus auch noch das Aussehen eines Widgets vollständig neu das Interface INotifyCollectionChanged definiert werden, wie zum Beispiel durch das implementieren. folgende ControlTemplate, welches einen Die TODO-Liste verwendet Objekte vom Typ Button in ein rotes Rechteck umdefiniert. TaskItem und TaskItemLists als Datenquel- tierung um die erforderlichen Interface- [...] Um eine Menge komplexer Objekte darzustel- len, empfiehlt sich der Einsatz eines Data- Template, welches die Datenbindung in die Vorlage integriert. Datenbindung Unter Datenbindung (englisch Data Binding) versteht man die Synchronisation zweier Da- tenpunkte. Ein Datenpunkt kann beispiels- Abb. 4 Von oben nach unten: Listeneintrag weise ein Objekt (Datenquelle) und der Name im Originalzustand, bei Mouseover und im einer Property (Anfrage an die Datenquelle) Editor-Modus. sein. In WPF wird ein Datenpunkt – die Quel- le der gebundenen Daten – durch die Klasse Mit diesen Erweiterungen sind Sie nun in der Binding repräsentiert. Die Attribute Source Lage, DataTemplates für die verschiedenen und Path repräsentieren die beiden oben be- Ansichten eines TaskItem (Abb. 4) zu imple- schriebenen Eigenschaften eines Datenpunkts: mentieren. Erstellen Sie als Fenster-Ressource ein DataTemplate für DataType="{x:Type
Verbinden Sie jede ListBox mit einer TaskI- in der Klasse XmlSerializer zur Verfügung temList und stellen sie Ihr eigenes Template stellt. als Template für die Listeneinträge ein. Implementieren Sie die Event Handler der ApplicationCommands zum Speichern und In-Place-Editieren von Einträgen Laden so, dass diese zunächst mit Hilfe des Standard-Datei-Dialogs den Dateinamen ab- Das Editor-Interface ist lediglich ein weiteres fragen und die Datei dann serialisieren oder DataTemplate, welches eine andere Darstel- deserialisieren. lung eines TaskItem zeigt. Verwenden Sie zur Eingabe von Titel und Beschreibung Textfel- der. Stellen Sie sicher, dass die Beschreibung Hinzufügen und Löschen von bei Bedarf umgebrochen wird. Wenn die Liste verbreitert wird, soll nur die rechte Spalte mit Einträgen den Eingabefeldern wachsen, nicht jedoch die Neue Einträge sollen über ein Kontextmenü Beschreibungen der Felder. wie in Abb. 5 erstellt werden. Definieren Sie ein solches Kontextmenü und weisen Sie es Sie werden feststellen, dass die Textfelder den vier Listen zu. Veränderungen Ihres Inhalts nur bei Verlust des Eingabefokus an das gebundene TaskI- tem weitergeben. Dieses Verhalten ist prob- lematisch, da so zum Beispiel beim Speichern von TODO-Listen Daten verlorengehen kön- nen. Konfigurieren Sie das Binding des Texts Abb. 5 Kontextmenü der Listen durch Modifikation seiner Property Update- SourceTrigger deshalb so, dass jede Ände- Wird die Aktion „Neu“ auf einer Liste ausge- rung direkt weitergegeben wird. führt, so soll an diese ein neuer Eintrag ange- Zur Eingabe des Fälligkeitsdatums bedienen hängt werden und dieser im Editier-Modus Sie sich des DatePickers aus der wpfsamp- dargestellt werden. leslib.dll. Der Namespace ist bereits im Die Aktion „Löschen“ ist nur dann verfügbar, Skelett importiert, so dass Sie einfach wenn das Kontextmenü auf einem bestehen- kbt:DatePicker verwenden können. Die den Element geöffnet wird. Ansonsten ist sie Einträge sollen über eine CheckBox als abge- deaktiviert wie in Abb. 5. schlossen markiert werden. „Löschen“ ist kein vordefiniertes Applica- Da ein selektierter Listeneintrag eine andere tionCommand. Definieren Sie daher ein eige- Hintergrundfarbe als ein unselektierter hat, nes RoutedUICommand in XAML als Ressource sollten Sie die Textfarbe ebenfalls anpassen. des Fensters. Die Methoden zur Ereignisbe- Um ein konsistentes Aussehen mit dem ak- handlung werden auf dieselbe Weise wie bei tuellen Farbschema des Betriebssystems zu vordefinierten Kommandos mit dem „code erzielen, verwenden Sie die Konstante Sys- behind“ verbunden. temColors.HighlightTextBrush. Setzen Sie das Kommando auch für den „Lö- Wenn der Benutzer einen Listeneintrag selek- schen“-Eintrag im Menü „Bearbeiten“ und den tiert, soll für diesen das Editor-Template an- Toolbar-Eintrag ein. Im Menü und in der gewandt werden. Dabei soll sichergestellt sein, Toolbar soll das Kommando dann aktiv sein, dass immer nur ein Element im Editor-Modus wenn ein Eintrag selektiert ist und dann die- ist, und zwar über alle vier Listen. Klickt der sen löschen. Benutzer also in eine andere Liste, wird der Verknüpfen Sie das Kommando weiterhin mit bisher geöffnete Editor geschlossen. der Taste „Entf“. Laden und Speichern von TO- Drag&Drop DO-Listen Um Einträge zwischen Listen verschieben zu Das Laden und Speichern der TODO-Liste als können, muss die Standardsequenz für XML-Datei ist verhältnismäßig einfach, da das Drag&Drop implementiert werden: .NET-Framework die gesamte Funktionalität Beim Klick auf ein Element sollten Sie die aktuelle Mausposition festhalten, um bei den 8
folgenden MouseMove-Ereignissen feststellen tion in einer Endlosschleife ab, beginnend mit zu können, ob die minimale Strecke zur Ein- dem Start der Anwendung. leitung einer Drag-Sequenz (SystemParame- Denken Sie sich als letztes eine Animation ters.MinimumHorizontalDragDistance, aus, die überfällige Einträge hervorhebt. Sie SystemParameters.MinimumVertical- sind in der Wahl Ihrer Animation völlig frei DragDistance) zurückgelegt wurde. Ist das und können auch algorithmisch komplexere der Fall, leiten Sie die Sequenz mit DoDragD- Pfade im C#-Code implementieren oder kön- rop und dem Effekt DragDropEffects.Move nen den graphischen Editor „Expression ein. Wird der Vorgang erfolgreich beendet, Blend“ verwenden. müssen Sie das entsprechende Element zwi- schen den beteiligten Listen verschieben. In der Behandlung des Ereignisses DragOver Internationalisierung müssen Sie darüber hinaus signalisieren, ob Internationalisierung ist heutzutage ein wich- die aktuelle Operation zulässig ist. In der TO- tiger Schritt bei der Programmentwicklung. DO-Liste soll DragDropEffects.Move er- Im .NET-Framework werden lokalisierte Res- laubt sein, wenn die verschobenen Daten ein sourcen, wie Zeichenketten, über sogenannte TaskItem sind, ansonsten soll keine Operati- Satellite Assemblies bereitgestellt. Der Res- on zulässig sein. sourcen-Editor von Visual Studio bietet Un- terstützung zur Erstellung solcher Assemblies. In C# kann auf diese Ressourcen zur Laufzeit Animationen über Eigenschaftsfelder von Proper- Animationen werden in XAML über soge- ties.Resources zugegriffen werden. Über- nannte Storyboards* definiert. Unter ande- legen Sie einen Moment, wie Sie diese Res- rem gibt es Animationen, die zwischen zwei sourcen in XAML verwenden können. Werten interpolieren, Animationen, die mit Wenn eine Benutzungsoberfläche bereits als Keyframes arbeiten, und eine Reihe speziali- XAML-Datei vorliegt, kann es jedoch beque- sierter Animationen. Eine Übersicht über all mer sein, die zu lokalisierenden Elemente aus diese findet sich in der MSDN Library†. dem XML-Code zu extrahieren. Dies über- Bauen Sie mit Hilfe eines EventTrigger eine nimmt das Tool LocBaml‡, welches in binärer Animation in die Standard-Ansicht der Lis- Form mit dem Programmskelett mitgeliefert tenelemente ein, die diese vergrößert, wenn wird. Die folgende Anweisung extrahiert alle die Maus über das Element bewegt wird, und Elemente, die mit dem eingangs erwähnten wieder verkleinert, wenn die Maus das Ele- Attribut x:Uid gekennzeichnet sind, in eine ment verlässt (Abb. 4). Gleichzeitig soll die CSV-Datei: Beschreibung unter dem Titel eingeblendet LocBaml.exe /parse de- werden, solange die Maus über dem Element DE/TODOListe.resources.dll ist. Stellen Sie sicher, dass die ausgeblendete Beschreibung keinen Platz einnimmt. Mit Dieser Befehl muss in dem Verzeichnis, in Hilfe der Storyboard-Attribute Accelera- dem das Executable liegt, ausgeführt werden. tionRatio und DecelerationRatio können Nachdem Sie die CSV-Datei mit den lokali- Sie den Beginn und das Ende Ihrer Animation sierten Zeichenketten aktualisiert haben, kann weicher gestalten. das LocBaml-Tool daraus eine entsprechende Animieren Sie weiterhin die Pfeile auf den Assembly generieren. Für eine englische Über- Beschriftungsachsen so, dass sich der Pfeil ein setzung sieht der Aufruf wie folgt aus: kurzes Stück in die Richtung, in die er zeigt, LocBaml.exe /generate de- und wieder zurück in seine Ausgangsposition DE\TODOListe.resources.dll bewegt. Aufgrund der drei Zustände lässt sich /trans:todoliste.resources.csv dies am besten durch eine Keyframe- /out:en-GB /cul:en-GB Animation realisieren. Spielen Sie die Anima- Erweitern Sie nun die Anwendung so, dass auf der Kommandozeile ein Ländercode nach RFC * http://msdn2.microsoft.com/en- 1766 angegeben werden kann und die Anwen- us/library/ms742868.aspx † ‡ http://msdn2.microsoft.com/en- http://msdn2.microsoft.com/en- us/library/ms752312.aspx us/library/ms746621.aspx 9
dung dann die entsprechende Sprache, sofern skelett automatisch. Bei Methoden und Funk- vorhanden, wählt. tionen sind die Parameter zu erklären. /// Literatur /// Short class description ANDERSON, CHRIS: Essential Windows Presen- /// (one sentence). tation Foundation. Boston: Addison-Wesley, /// /// Extended descriptions 2007. /// NAGEL, CHRISTIAN; EVJEN, BILL; GLYNN, JAY; class Example { SKINNER, MORGAN; WATSON, KARLI: Profes- [...] sional C# 2005 with .NET 3.0. Indianapolis: } Wiley, 2007. /// /// Short method description Programmierrichtlinien /// (one sentence). Bitte halten Sie sich beim Programmieren an /// die nachstehenden Richtlinien – die Richt- /// Extended descriptions linienkonformität geht in die Bewertung Ihrer /// Lösung mit ein! Bitte beachten Sie, dass sich /// die Richtlinien je nach Programmiersprache /// Defines von Aufgabenblatt zu Aufgabenblatt leicht /// the type of the shape: /// 0=precise, 1=fast approximation unterscheiden können. /// /// Number of matching Sprache /// datasets. Kommentare und sämtliche Bezeichner sind int GetNumberOfExamples(int in Englisch verfassen. accuracy) { [...] } Zeilenlänge und Einrückung Die Zeilenlänge darf 80 Zeichen nicht über- Namenskonventionen schreiten. Generell: Bitte „CamelCase“ verwenden, Die Einrückungstiefe beträgt vier Leer- zum Beispiel CamelCaseLooksLike- zeichen. This. Kurze Kommentare Klassen und Interfaces: Einfache Subs- tantive in UpperCamelCase. Kurze Kommentare dienen zur Verbesserung der Lesbarkeit des Codes: Öffentliche Methoden und Properties: Einfache Verben oder sprechende Be- if (a == 2) { zeichnungen, in UpperCamelCase. return TRUE; /* special case */ Sonstige Methoden: Einfache Verben } else { oder sprechende Bezeichnungen lo- return isPrime(a); /* works only for odd 'a' */ werCamelCase. } Variablen: Möglichst kurze „sprechen- de“ Bezeichnungen in lowerCamelCa- Der ersten Kommentar sollte beispielsweise se. nicht lauten: /* if a=2 then return true */. Temporäre Variablen dürfen auch ein Zeichen wie „i“ als Namen haben. Klassen-, Methoden- und Funkti- Konstanten: Großbuchstaben mit „_“ als Worttrennzeichen wie zum Beispiel onskommentare static readonly int MAX_WIDTH = Verwenden Sie die XML-Kommentare von 100; Visual Studio für Klassen und Methoden. Wenn Sie über einer Deklaration „///“ einge- ben, erzeugt der Editor ein Dokumentations- 10
Kontrollfragen Sie müssen mindestens die Hälfte der folgenden Fragen richtig beantworten, um weiterzukom- men. Eine Frage gilt dann als richtig beantwortet, wenn genau die richtigen Antworten markiert sind. Es können beliebig viele Antworten pro Frage richtig sein, also auch keine oder alle. 1. Welche der folgenden Varianten, den Event this.StuffHappened zu feuern, ist sicher? if (this.StuffHappened != null) TheHandler h = null; this.StuffHappened(); if ((h = this.StuffHappened) != null) h(); TheHandler h = this.StuffHappened; this.StuffHappened(); if (h != null) h(); 2. Welche Aussagen über die Ereignisbehandlung durch WPF sind zutreffend? Die Event-Handler werden im „code be- Die Event-Handler werden mit Hilfe des hind“ anhand ihres Namens identifiziert. Reflection-API angesprochen. Die Event-Handler werden im „code be- Ereignisse können sowohl in der Tunnel- hind“ zur Compile-Zeit mit der Oberfläche als auch in der Bubble-Phase bearbeitet fest verbunden. werden. 3. Die Zeilen einer Tabelle sollen in WPF mit einem vertikalen Schriftzug beschriftet werden. Der Programmierer wendet dazu ein RenderTransform auf ein Label an. Welches Ergebnis tritt warum ein? Die Beschriftungsspalte ist zu breit und zu Der Text passt exakt in die Beschriftungs- niedrig, weil die Transformation unmittel- spalte, weil die Transformation vor dem bar vor der Darstellung angewendet wird. Layout angewendet wird. Die Beschriftung ist falsch orientiert, weil Die Beschriftungsspalte ist zu breit, weil die die Font-Rasterierung vor der Geometrie- Transformation vor dem Layout angewen- transformation erfolgt. det wird. 4. Kann und darf das Items-Eigenschaftsfeld einer ListBox manipuliert werden? Ja, aber nur wenn keine Datenbindung für Nein, es muss grundsätzlich die Items- die Elemente aktiv ist. Source-Property verwendet werden. Ja, aber immer nur indirekt über die Sour- Nein, Items kann nicht geändert werden, ceCollection-Property von Items. weil es keinen set-Zugriff hat. 5. Was ist DockPanel.Dock? Attached Property Extension Method Markup Extension System.Attribute 6. Das statische Objekt App.TheStuff hat eine string-Eigenschaft Name und ist DataContext einer TextBox. Welche der folgenden Data Bindings funktionieren innerhalb der TextBox? Text="{Binding Path=Name, Text="{Binding Source={TheStuff}, UpdateSourceTrigger=Default}" Path=Name}" Text="{Binding Source={x:Static Text="{Binding Source={x:Static l:App.TheStuff}, Path=Name}" App.TheStuff} Path=Name UpdateSourceTrigger=Default}" 7. Was trifft für Commands zu? Sie müssen ihre Aktion in einer Methode Ihre Handler haben eine vom auslösenden Run ausführen. Ereignis unabhängige Signatur. Sie können mit Shortcuts versehen werden. Sie können immer ausgeführt werden. 11
Bewertungskriterien Punkte Der komplette Quellcode ist standardkonform und objektorientiert. Er enthält keine 3 offensichtlichen Speicher- und Ressourcenlecks oder offensichtlich semantisch falsch verwendete Sprachkonstrukte. Das Programm ist in sinnvoller Weise dokumentiert und befolgt die Programmierricht- linien. Es lässt sich im VISGS-Pool mit den vorgegebenen Compiler-Einstellungen feh- ler- und warnungsfrei (Compiler- und Linkerfehler und -Warnungen) übersetzen. Das Programm lässt sich ohne Speicherschutzverletzungen, Exceptions oder andere 1 Laufzeitfehler im VISGS-Pool ausführen. Das Layout des Hauptfensters entspricht dem Screenshot der Musterlösung. Die Pfeile 3 auf dem Rand sind animiert. Alle Oberflächenelemente wurden in XAML definiert. Es gibt ein Menü und eine Toolbar, über die jeweils eine TODO-Liste aus einer XML- 2 Datei geladen oder in eine solche geschrieben werden kann und über die die Anwen- dung beendet werden kann. Die Buttons in der Toolbar haben Tooltips. Für die Aktio- nen werden die entsprechenden vordefinierten Kommandos verwendet. Durch Klicken eines Items wird ein In-Place-Editor-Formular anzeigt, über das der 4 Titel, die Beschreibung, das Fälligkeitsdatum sowie der Bearbeitungsstatus geändert werden kann. Der Wechsel zwischen der einfachen Listenanzeige und dem Editor- Formular erfolgt in XAML. Es ist insgesamt immer nur ein Eintrag editierbar. 2 Die angezeigten Daten sowie die Daten in der Editor-Ansicht sind über DataBindings 4 in XAML realisiert. Über das Kontextmenü der Listen können neue Einträge erzeugt werden, deren Wich- 2 tigkeit und Dringlichkeit implizit durch die Listenzugehörigkeit gegeben ist. Das neue Element befindet sich zu Beginn im Editor-Modus. Die Einträge können zwischen den Listen per Drag&Drop verschoben werden. Da- 3 durch ändern sich die Wichtigkeit und die Dringlichkeit der Einträge. Es gibt ein benutzerdefiniertes RoutedUICommand, mit dem der aktuell selektierte 2 Eintrag gelöscht wird. Es ist zugänglich über die „Entf“-Taste, das Menü „Bearbeiten“, das Kontextmenü und eine separate Toolbar (mit Tooltip). Das Kommando ist nur dann aktiv, wenn ein Eintrag selektiert ist und darüber hinaus im Falle des Kontext- menüs dasselbe über einem Eintrag aktiviert wurde. Eine Animation und eine andere Farbe des Titels machen den Benutzer auf überfällige 1 Einträge (IsOverdue == true) aufmerksam. Abgeschlossene Einträge werden durch einen durchgestrichenen Titel und eine andere Farbe hervorgehoben. Nur die Anima- tion ist, falls erforderlich, im C#-Quelltext realisiert. Wird die Maus über einen Eintrag bewegt, so wird dessen Titel größer und es wird 2 zusätzlich darunter die Beschreibung angezeigt. Dies ist in XAML realisiert. Neben der deutschen Version der Anwendung gibt es noch mindestens eine weitere 1 Lokalisierung (z. B. englisch), die über eine Satellite Assembly realisiert ist. Gesamtpunktzahl 30 12
Sie können auch lesen