Fachpraktikum Graphische Benutzungsoberflächen Aufgabe 3: TODO-Liste mit WPF

Die Seite wird erstellt Henrik Singer
 
WEITER LESEN
Fachpraktikum Graphische Benutzungsoberflächen Aufgabe 3: TODO-Liste mit WPF
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