WPF Einführung
WPF- Windows Presentation Foundation
Mit dem Betriebssystem Windows Vista wurde die .NET Bibliothek WPF
eingeführt. Es ist der Versuch, die Implementierung nativer
Windows- Clients in technischer als auch organisatorischer Sicht auf
eine modernere Grundlage zu stellen. Es werden folgende Ziele
angestrebt:
Einsatz der umfangreichen Hardwarebeschleunigung durch
moderne Grafikkarten in der Implementierung
einfache Implementierung von Farbverläufen, Animationen
und gedrehten/verzerrten Steuerelementen in der GUI
bessere Ausnutzung der Bildschirmfläche durch Layouts,
die sich an die Fenstergröße anpassen
einfache Generierung von druckbaren Dokumenten
Implementierung von 3D Objekten in der GUI
Oberflächenentwurf unabhängig von den Werkzeugen
des Programmierers machen
Zugriff auf die GUI über das Internet (Option: Ausführen
im Webbrowser)
Windows Forms und WPF – eine
Gegenüberstellung
Das folgende Schichtenmodell zeigt die Unterschiede bei der
Implementierung einer Windows- Form und einer WPF- Anwendung.
DirectX, milcore etc.
Durch Zugriff auf die Grafikhardware über DirectX in WPF
können die Ressourcen moderner Grafikkarten voll ausgenutzt
werden, um auch anspruchsvollere grafische Operationen wie
Farbverläufe, gedrehte Schriften und 3D- Objekte in modernen
Geschäftsanwendungen zu anzubieten.
Ein Teil der WPF- Implementierung ist unterhalb der CLR
implementiert und damit unverwaltet. Hier sind Operationen
ausgelagert, die eng mit DirectX verzahnt sind und äußerst
ressourcenintensiv sind.
Die Mehrzahl der WPF- Klassen ist jedoch oberhalb der CLR, und
damit verwaltet implementiert.
Durch diese Aufteilung des WPF- Codes in verwalteten und
unverwalteten Code soll die Entwicklungs- und Portierungsarbeiten
minimiert, und die Effizienz bei der Ausführung maximiert
werden.
Aufteilung der Entwicklungsarbeit durch XAML
In einer WPF- Anwendung kann das Design der GUI komplett in einer
XAML- XML- Datei beschrieben werden. XAML stellt damit eine XML-
Schnittstelle zwischen der Welt der .NET Programmierer und der Welt
der Grafiker und Designer mit ihren Lieblingstools wie Dreamwaver ©
etc. dar. So könnte ein Desinger die GUI mit seinem Tool in HTML
entwerfen. Anschließend könnte diser Entwurf durch eine
entsprechende Stylesheet- Datei in eine XAML- Beschreibung
umgewandelt werden. Damit ergibt sich rein theoretisch eine strikte
Trennung zwischen Oberflächenentwurf und Implementierung der
Anwendungslogik.
Klassenhierarchie und Basisklassen
Durch Basisklassen werden in der WPF Prinzipien wie STA, Vererbung
von Eigenschaftswerten, Flexible Layouts , Steuerelemente mit
allgemeinen Inhalten und deklarative Programmierung eingeführt.
Hier ein Ausschnitt aus der Klassenhierarchie von WPF:
STA und System.Threading.DispatcherObject
STA steht für Single Thread Apartment. Jedem STA ist
ein Thread zugeordnet. Nur dieser darf auf die Objekt innerhalb eines
STA zugreifen. Aus anderen Threads gelingt der Zugriff nur mittels
Marshalling (implementiert z.B. durch eine MessageQueue).
Daraus folgt, das STA- Anwendungen nicht reentrant sein müssen.
Klassische Windows- Forms- Anwendungen, die die
Nachrichtenwarteschlange auslesen und in Fensterfunktionen
verarbeiten sind typische Vertreter für STA. Im folgenden
nochmals ein Vergleich zwischen MTA und STA:
MTA- Multi Thread Apartment
STA – Single Thread Apartment
DispatcherObject
Aus Gründen der Kompatibilität mit der GDI und dem
Windows- Betriebssystem laufen WPF- Applikationen in STA. Die
DispatcherObject- Klasse ist dafür die Grundlage. Sie
bietet z.B. Methoden wie CheckAccess an,
mit denen die Gültigkeit des Methodenaufrufes eines WPF-
Objektes aus dem aktuellen Thread heraus geprüft werden kann.
Delegieren des Setzens
von WPF- Eigenschaften an den UI- Thread
Ein Anwendung findet das
Dispatcher- Objekt in Situationen, wo eine WPF- Eigenschaft aus einem
nicht- UI- Thread heraus gesetzt werden muss, beispielsweise einem
System.Timers.Timer- Thread. Hier kann mit der Mehtode
Invoke
der Aufruf an den UI- Thrad
delegiert werden.
System.Timers.Timer clock = new System.Timers.Timer(1000.0);
public Window1()
{
InitializeComponent();
// Timer einrichten
clock.AutoReset = true;
clock.Elapsed += new System.Timers.ElapsedEventHandler(clock_Elapsed);
clock.Enabled = true;
}
// Eventhandler, der im Timer- Thread aufgerufen wird, und nicht im UI- Thread!
void clock_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// Das Setzen der Label- Eigenschaft wird an den UI Thread delegiert.
// Dieses Vorgehen wird durch das STA erzwungen
Dispatcher.Invoke(
new Action<string>(time => lblStatusTime.Content = time),
new object[] {DateTime.Now.ToLongTimeString()});
}
Eigenschaftsvererbung, Trigger als
DependencyProperties
durch DependencyObject implementieren
In der WPF wird der imperative
Programmierstil (Folge von DrawLine(...) etc. Funktionsaufrufen)
durch einen deklarativen, DOM- geprägten Stil verdrängt
(Aufbau eines WPF- Objektbaumes new Line(..) etc.). Die
Parametrierung der der WPF- Instanzen tritt in den Vordergrund.
<Menu Name="menu1"
VerticalAlignment="Top"
Grid.Row="0"
FontFamily="Times New Roman" FontSize="16pt" > ----+
<MenuItem Name="mnuItemFile" Header="_Datei"> <-+ erben
<MenuItem Name="mnuFileOpen" |
Header="Ö_ffnen" |
FontStyle="Italic" | Überschreiben mit
Click="MenuItemFileOpen_Click"/> | lokaler Eigenschaft
</MenuItem> |
<MenuItem Name="mnuItemEffects" Header="_Effekte"> <-+ erben
<MenuItem Name="mnuItemEffektGlow" <-+ erben
Header="Bring es zum Glühen"
Click="mnuItemEffektGlow_Click"/>
</MenuItem>
</Menu>
In WPF- Objektbäumen ist das
vererben von Eigenschaftswerten an die Kind- Elemente
sinnvoll. Hat ein Wurzelelement die Eigenschaft FontSize, so
können die Kindelemente diese übernehmen, wodurch der
Umfang bei der Definition der Objektbäume gemindert wird. Da
WPF- Anwendungen "leben", indem sie z.B. auf
Benutzereingaben reagieren, muss auch auf eine sich ändernden
FontSize eines Elternelementes in den Kind- Elementen reagiert
werden.
Eigenschaftswerte von WPF- Objekten
errechnen sich aus dem Kontext, in dem das WPF-Element steht. Der
implementierende Mechanismus unterscheidet sich fundamental von den
Bekannten Eigenschaften der CLR- Sprachen wie C#. Folgendes Bild
skizziert die Funktionsweise der DependencyProperties von WPF
Rendern von WPF-Objektbäumen mit maximaler
Hardwarebeschleunigung- Visual
Die durch DirectX angesteuerte
Grafikhardware arbeitet nach einem "Maler"- Algorithmus:
Zuerst werden die Elemente des Hintergrundes gezeichnet, dann darüber
die Elemente des Vordergrundes (Kindelemente). Sind die Kindelemente
zu einem bestimmten Teil transparent, dann wird dies durch die
Grafikhardware beim überzeichnen realisiert.
DirextX basiert damit auf einem
hierarchischen Modell. Die Knoten in dieser Hierarchie werden
Strukturknoten genannt. Die Wurzel ist der gesamte
Bildhintergrund, und die Blattelemente stehen unmittelbar im
Vordergrund.
Visual Basisklasse
Die Visual Basisklasse ist
vergleichbar mit einer Fensterhandle in Win32: Sie zeigt auf eine
Menge von Strukturknoten im milcore, aus denen das von Visual
abgeleitete WPF- Objekt gerendert wird.
Layout-Modelle und
innovative Ereignisverarbeitung: UIElement
Die Basisklasse UIElement erweitert die
WPF um folgende Funktionen:
Layout-Modelle
Verarbeitung von GUI- Ereignissen
Layout-Modelle
Kind – Steuerelemente
können in der WPF nach beliebigen Regeln auf der
Präsentationsoberfläche angeordnet werden. Dieses flexible
Layout wird durch einen zweistufigen Prozess erreicht, den die
Basisklasse
UIElement implementiert.
Stufe
|
Operation
|
Details
|
1
|
UIElement.Measure(Size availableSize)
|
Die Methode wird von dem Elternelement aufgerufen. Innerhalb
des zur Verfügung stehenden Rechtecksfläche werden die
benötigte Rechtecksfläche bestimmt, und in der
Eigenschsft DesiredSize bereitgestellt.
Grundsätzlich wird nur eine
Fläche beansprucht, die minimal zur Darstellung des Inhaltes
vom Steuerelement benötigt wird.
|
2
|
UIElement.Arrange(Rect finalRect)
|
Die Kindelemente werden innerhalb der zur Verfügung
stehenden Rechteckfläche neu angeordnet.
|
In der WPF werden bereits spezielle
Implementierungen für Layouts in Form von Container- Klassen
mitgeliefert wie Grid und WrapPanel.
Verarbeitung von GUI- Ereignissen
Durch eingaben auf der Benutzeroberfläche werden im Windows
Betriebssystem User32 Nachrichten generiert und an die
Nachrichtenwarteschlange der betroffenen Anwendung weitergeleitet.
Ist die Anwendung eine WPF- Anwendung, dann werden die User32-
Nachrichten in zwei WPF- Ereignisse konvertiert:
Vorschauereignis
tatsächliches Ereignis
Das Vorschauereignis wird dabei, von der WPF- Objektbaumwurzel
beginnend, absteigend an jedes Element übergeben, das auf dem
Weg zu dem Element liegt, das mit dem Fensterausschnitt auf dem
Bildschirm korrespondiert, in dem die Eingabe ursprünglich
stattfand. Diese Weiterleitung von der Wurzel zum Kindelement wird
Tunnelprinzip genannt.
Das tatsächliche Ereignis wird
zuerst an das betroffene Kindelement im Objektbaum ausgelöst,
und dann aufsteigend bis zur Wurzel an alle Eltern- und
Großelternelemente.
Resourcen verwalten mit FrameworkElement
XAML
Einführung
XAML ist das Akronym aus Extensible Application Markup
Language. Es ist ein von der Firma Microsoft entwickeltes XML
Vokabular, mit dem grafische Benutzeroberflächen beschrieben
werden können.
Ursprünglich wurde XAML für die WPF- Bibliothek
entwickelt. XAML ist auch unabhängig von .NET und WPF
einsetzbar. So können einfache XAML- Dateien analog HTML Dateien
von Browsern wie IE oder Firefox interpretiert und dargestellt
werden. Grundlage dafür ist eine Aufteilung des Vokabulars
bezüglich der Funktionalität durch XML- Namespaces:
Präsentation
Um die Oberfläche einer WPF- Anwendung zu Beschreiben, die im
folgenden Namensraum eingeschlossene Teilmenge ausreichend:
<?xml version="1.0" encoding="utf-8" ?>
<StackPanel xmlns="http://schemas.microsoft.com/netfx/2007/xaml/presentation" >
…
</StackPanel>
Präsentation und Anwendungslogik
Die Definition von z.B. von Eventhandler für Steuerelemente
erfordert ein zusätzliches XAML- Vokabular. Dieses ist in den
Namensraum mit dem Präfix x eingeschlossen.
<?xml version="1.0" encoding="utf-8" ?>
<StackPanel xmlns="http://schemas.microsoft.com/netfx/2007/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button Name="btnJava" Click="btnJava_Click" >Click mich</Button>
<x:Code>
<![CDATA[
private void btnJava_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hallo");
}
]]>
</x:Code>
</StackPanel>
Silverligth
Silverligth ist ein Browser- Plugin, das eine Teilmenge der WPF
implementiert. So können Vektorgrafiken und Animationen für
Webanwendungen, basierend auf .NET implementiert werden. Das XAML-
Vokalbular für Silverlight ist eine Teilmenge des XAML-
Vokabulares von WPF. Es ist in folgenden Namespace eingeschlossen:
<UserControl x:Class="SilverlightApplication1.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot" Background="White">
</Grid>
</UserControl>