Dienstag, 22. Mai 2012


Artikel

Dezember 2007 | Artikel

WPF intim Fortsetzung, Teil 2

Teil 1   Teil 2   

XAML-Code ausspionieren

Im Gegensatz zu C#- oder Visual-Basic- Code wird XAML-Code nicht nach MSIL kompiliert, sondern lediglich in ein effizienteres binäres Format übersetzt. Dieser Binärdatei wird dann in der Assembly der Anwendung als Ressource hinterlegt. Jetzt könnte man auf die Idee kommen, auch eigene Ressourcen auf diese Weise zu laden oder XAML-Ressourcen aus anderen Anwendungen zu extrahieren. Dazu müsste lediglich ein Uri-Objekt für die Ressource der anderen Anwendung erzeugt und darauf die Methode LoadComponent() angewendet werden. Listing 5 skizziert diese Vorgehensweise:

Bei der Angabe der URI muss lediglich noch der Name der Assembly angegeben werden. Auf diese Weise können Ressourcen auch aus anderen Dateien geladen werden. Im Gegensatz zum letzten Aufruf der Methode LoadComponent() wird diesmal der Rückgabewert in ein Window-Objekt umgewandelt, vorausgesetzt, das Wurzelelement der XAML-Datei ist tatsächlich von diesem Typ. Danach wird ein Stream geöffnet (im Speicher oder in eine Datei) und mittels eines XamlWriters der Binärcode des XAMLObjekts (hier vom Typ Window) als Textrepräsentation in den Stream geschrieben. Abbildung 1 zeigt den aus einer Assembly extrahierten XAML-Code innerhalb einer RichText-Komponente an:

Dieser entspricht ziemlich genau dem Original, außer das als Alias für den WPF-Namespace das Kürzel av verwendet wird.

Dies hat natürlich Auswirkungen, was die Sicherheit einer Anwendung angeht und es führt zu neuen Möglichkeiten, XAML-Ressourcen nachzuladen. XAML-Code ist demnach standardmäßig nicht mehr oder weniger geschützt, wie MSIL-Code. In diesem Fall ist es sogar ein zusätzlicher Nachteil, dass der XAML-Code nicht nach MSIL übertragen wird, da sich Assembly- Ressourcen noch wesentlich einfacher extrahieren lassen. Eine Lösung zur Verbesserung der Sicherheit könnte die Verwendung der Klasse XamlReader sein, die XAML-Code aus einer Textdatei laden und in eine Objektrepräsentation übertragen kann.

XAML lesen und schreiben

Die beiden Klassen XamlReader und Xaml- Writer erlauben das Lesen und Schreiben von XAML aus und in Streams in Markup- Syntax. Ein XamlReader erzeugt als Ergebnis ein Objekt vom Typ des Wurzelelements des XAML-Codes während ein XamlWriter ein solches Objekt als Argument nimmt und es als Markup in den Stream schreibt. Durch die Verschachtelung von Streams ist es nun möglich, Teile der Anwendung als verschlüsselte und optional gepackte Ressourcen abzuspeichern, diese zur Laufzeit laden, entschlüsseln, über einen XamlReader einzulesen und das Ergebnis in die Anwendung zu integrieren.

Umgekehrt bietet der XamlWriter z.B. die Möglichkeit, einen kompletten Objektbaum im Code (mit C# oder Visual Basic) zu erzeugen und diesen dann als Markup in eine Datei zu schreiben. Damit ließe sich z.B. eine aufwändige Animation oder eine 3D-Grafik im Code erzeugen, als XAML speichern und diese als "Loose XAML" im Internet oder Intranet bereitstellen, sodass sie über einen Browser geladen werden kann. Der Fantasie sind wie immer keine Grenzen gesetzt. Der Code aus Listing 6 könnte sich in einer externen XAML-Datei befinden. Er soll den vollständigen Inhalt eines Fensters beinhalten, der hier allerdings nur aus Layout-Container sowie zwei Komponenten besteht.

Das Hauptfenster wird in XAML lediglich aus einem Window-Element erzeugt, welches keinen weiteren Inhalt besitzt. Nach dem Laden des Hauptfensters (Ereignis Loaded) oder einem anderen Zeitpunkt kann jetzt der Inhalt der XAML-Datei (oder einer XAML-Ressource in der Assembly) geladen und in den Elementbaum integriert werden. Im einfachsten Fall wird dazu der Inhalt über einen File- Stream bereitgestellt, welcher der Methode Load() des XamlReaders als Eingabe übergeben wird. Die Methode liefert als Resultat ein Objekt vom Typ des Wurzelelements zurück, welches allerdings noch in diesen Typ umgewandelt werden muss, um es einer entsprechenden Variablen zuzuweisen. Danach kann der Stream wieder geschlossen werden. Um Komponenten, die sich in der XAML-Datei befinden mit einem Ereignishandler zu versehen, ließe sich z.B. die Methode FindName() verwenden, wenn die Komponenten einen Namen besitzen. Zum Abschluss kann der Inhalt des Hauptfensters (oder einer anderen Komponente) mit dem Inhalt der XAML-Datei versehen werden (this.Content = sp;). Der Inhalt des Fensters stammt jetzt vollständig aus dem Markup einer externen XAML-Datei.

XAML = XML

Dieser Exkurs in die Interna einer WPF-Anwendung sowie dem Laden und Speichern von XAML zur Laufzeit sollte reichlich Stoff für Ideen geben. Ein großer Vorteil von XAML ist bekanntlich, dass es sich um pures XML handelt. Dementsprechend einfach ist das automatisierte Generieren und Verarbeiten von XAML-Code. Dieser Code kann zum Beispiel mit dem Xaml- Reader geladen und in eine Anwendung integriert werden. Wurde innerhalb einer Anwendung z.B. eine Vektorgrafik erzeugt, könnte die Grafik als Baum von WPF-Grafikelementen erzeugt und mit dem Baum in einer XAML-Datei gespeichert werden. Damit liegt nicht nur ein gut verarbeitbares Austauschformat vor, die Grafik lässt sich auf vielfältige Weise in andere WPF-Anwendungen integrieren, z.B. als Hintergrundbild. Soll verhindert werden, dass der XAML-Code allzu einfach durch andere gelesen werden kann, kann er z.B. verschlüsselt abgelegt werden und muss dann manuell geladen und in den Elementbaum "eingehängt" werden. Natürlich könnte man auch einfach auf die Verwendung von XAML verzichten und sämtliche Anweisungen im Code hinterlegen und darauf einen Obfuscator anwenden. Absolut sicher werden diese Maßnahmen den Code aber auch nicht machen können.

Nachdem Dirk Frischalowski sein Buch zur WPF endlich fertig gestellt hat, widmet er sich voller Elan dem nächsten Projekt: Einem Buch zu Expression Blend. Das wird allerdings noch etwas dauern. Bereits begonnen hat er damit, sein lange angekündigtes WPF-Tutorial unter www.gowinfx .de wieder aufleben zu lassen.

Links & Literatur

[1] Dirk Frischalowski: Windows Presentation Foundation. Grafische Oberflächen mit .NET 3.0, Addison-Wesley 2007

Teil 1   Teil 2   

Kommentare