## 22.3 Brush-Objekte Die grafischen Elemente, auf die wohl am häufigsten zugegriffen wird, sind die Brush-Elemente, zu Deutsch auch Pinsel genannt. Sie beschreiben die Darstellung von Hintergründen, Füllmustern und auch anderer grafischer Elemente. Die Basis aller Füllmuster ist die Klasse Brush, die zum Namespace System.Windows.Media gehört. Die Klasse Brush ist abstrakt definiert und stellt neben anderen Eigenschaften auch die Möglichkeit zur Verfügung, mit der Eigenschaft Opacity die Transparenz einzustellen. Brush wird durch TileBrush, GradientBrush und SolidColorBrush abgeleitet. Die beiden erstgenannten Klassen sind ihrerseits selbst abstrakt und dienen nur der Bereitstellung weiterer Gemeinsamkeiten an deren Ableitungen. Die Hierarchie sehen Sie in Abbildung 22.7. Eine Kurzbeschreibung der Klassen finden Sie in Tabelle 22.3. Wir werden uns im Verlauf dieses Kapitels die Klassen noch etwas genauer ansehen.

Tabelle 22.3 Die konkreten Ableitungen der Klasse »Brush«

Klasse | Beschreibung
DrawingBrush | Dient zur Füllung eines Bereichs mit grafischen Elementen, Videos und Bildern.
ImageBrush | Füllt einen Bereich mit Bildern.
LinearGradientBrush | Wird verwendet, um einen linearen Farbverlauf darzustellen.
RadialGradientBrush | Wird verwendet, um einen radialen Farbverlauf darzustellen.
SolidColorBrush | Dient zum Füllen mit genau einer Farbe.
VisualBrush | Füllt einen Bereich mit einem grafischen Element.
Hier klicken, um das Bild zu vergrößern Abbildung 22.7 Die Hierarchie der Brush-Klassen ### 22.3.1 SolidColorBrush Möchten Sie eine Fläche mit einer Farbe füllen oder Linien in einer bestimmten Farbe zeichnen, verwenden Sie SolidColorBrush. Geben Sie die Farbe an, können Sie auf die vordefinierten Eigenschaften der Klasse Brushes zurückgreifen, beispielsweise:
    <Rectangle Width="100" Height="60">
      <Rectangle.Fill>
        <SolidColorBrush Color="BlanchedAlmond" />
      </Rectangle.Fill>
    </Rectangle>
Der gewünschte Farbwert wird mit der Eigenschaft Color angegeben. Er kann auch ein Hexadezimalwert sein:
    <SolidColorBrush Color="#AA8790" />
Bei der Angabe eines Hexadezimalwertes können Sie neben dem eigentlichen Wert des Farbtons die Angabe auch um eine Transparenz erweitern. Beabsichtigen Sie, eine Farbe mit 50 % Transparenz anzuzeigen, würde der Farbton wie folgt beschrieben:
    <SolidColorBrush Color="#80AA8790" />
Hier wird einfach vor der sechsstelligen Hexadezimalzahl der Farbe eine zweistellige Transparenz für den sogenannten Alphakanal angegeben. Alternativ bietet sich auch die gleichwertige Übergabe der Transparenz an die Eigenschaft Opacity an:
    <SolidColorBrush Opacity="0.5" Color="#AA8790" />
### 22.3.2 LinearGradientBrush Die Klasse LinearGradientBrush beschreibt einen Farbverlauf zwischen zwei Punkten. Die Achse des Farbverlaufs wird als Verlaufslinie oder auch Gradientenachse bezeichnet. Diese Linie gibt die Richtung des Farbverlaufs an und wird durch die Eigenschaften StartPoint und EndPoint beschrieben. Die Definition des Koordinatensystems für den Gradienten sehen Sie in Abbildung 22.8. Hier klicken, um das Bild zu vergrößern Abbildung 22.8 Koordinatendefinition Ein Gradient, der von links nach rechts verlaufen soll, beginnt im Punkt 0,0 und endet im Punkt 1,0. Ein diagonaler Verlauf von rechts unten nach links oben beginnt im Punkt 1,1 und endet im Punkt 0,0. Um den Effekt des Gradienten zu erfahren, betrachten Sie Abbildung 22.9, in der vier Rechtecke eine jeweils anders verlaufende Gradientenachse haben. Von links nach rechts sind die Farbverläufe wie folgt definiert:
    <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
    <LinearGradientBrush StartPoint="1,1" EndPoint="0,0">
    <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
Hier klicken, um das Bild zu vergrößern Abbildung 22.9 Farbverläufe mit unterschiedlichen Gradientenachsen Einen Farbverlauf zu produzieren bedeutet, mindestens zwei Farben anzugeben. Hierzu wird die Klasse GradientStop benötigt. Diese versetzt uns sogar in die Lage, beliebig viele Zwischenpunkte innerhalb des Farbverlaufs festzulegen. Der relative Punkt auf der Gradientenachse wird mit der Eigenschaft Offset angegeben, die zwischen dem Startpunkt 0 und dem Endpunkt 1 liegen muss. Für jedes GradientStop-Element wird mit Color die gewünschte Farbe in dem betreffenden Punkt beschrieben. Sehen wir uns zuerst einen einfachen Farbverlauf von Weiß nach Grau an:
    <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
      <GradientStop Offset="0.0" Color="White" />
      <GradientStop Offset="1.0" Color="Black" />
    </LinearGradientBrush>
Die Darstellung entspricht dann der des linken Quadrats in Abbildung 22.9. Beeindruckender sind natürlich Farbverläufe mit mehreren Verlaufsänderungen. Dazu geben Sie die Zwischenstopps ebenfalls durch GradientStop-Elemente unter Nennung der Farbe an. Die Position des Zwischenstopps wird ebenfalls durch Offset beschrieben, was dann natürlich zwischen 0 (dem Startpunkt der Gradientenachse) und 1 (dem Endpunkt der Gradientenachse) liegen muss. Da Offset vom Typ Double ist, können Sie den Zwischenstopp sehr präzise festlegen. Im folgenden Listing sind zwei Zwischenstopps in den Farben Grau und Blau in dem an sich ansonsten von Weiß nach Schwarz definierten Farbverlauf enthalten.
    <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
      <GradientStop Offset="0.0" Color="White" />
      <GradientStop Offset="0.4" Color="Gray" />
      <GradientStop Offset="0.6" Color="Blue" />
      <GradientStop Offset="1.0" Color="Black" />
    </LinearGradientBrush>
In Abbildung 22.10 sehen Sie den Farbverlauf. Hier klicken, um das Bild zu vergrößern Abbildung 22.10 Mehrstufiger Farbverlauf
Hinweis
Je nach Farbwahl und der zu füllenden Fläche sind manchmal recht deutliche Sprünge im Farbverlauf zu erkennen. Diese können unter Umständen mit der Einstellung ScRGBLinearInterpolation der Eigenschaft ColorInterpolationMode beseitigt oder doch zumindest deutlich reduziert werden.
### 22.3.3 RadialGradientBrush Die Klasse RadialGradientBrush ähnelt der zuvor beschriebenen Klasse LinearGradientBrush mit dem Unterschied, dass keine rechteckigen Grundrisse gefüllt werden, sondern runde. Für die Angabe des Farbverlaufs benutzt man erneut die Klasse GradientStop. Auch hier werden die Koordinaten zwischen 0,0 und 1,0 angegeben und beziehen sich (zunächst) auf den Mittelpunkt des zu füllenden Objekts. Sie können den Bezugspunkt aber auch mit GradientOrigin beliebig verschieben. Mit 0.0, 0.0 befindet er sich wie bei einem rechteckigen Umriss in der linken oberen Ecke. Folglicherweise wird der Punkt 0.5, 0.5 dem Mittelpunkt der Ellipse entsprechen. Zur Verdeutlichung der Eigenschaft GradientOrigin werden wieder Farbverläufe von Weiß nach Blau beschrieben. Die vier XAML-Zeilen beschreiben die Kreise (besser: Kugeln), die in Abbildung 22.11 von links nach rechts zu sehen sind.
    <RadialGradientBrush>
    <RadialGradientBrush GradientOrigin="0.3, 0.3">
    <RadialGradientBrush GradientOrigin="0.5, 0.5">
    <RadialGradientBrush GradientOrigin="0.8, 0.8">
Hier klicken, um das Bild zu vergrößern Abbildung 22.11 Die Auswirkungen von »GradientOrigin« Optisch erinnert die Ausgabe an die Bestrahlung durch einen Scheinwerfer. Mit weiteren Eigenschaften von RadialGradientBrush lässt sich der Lichtkegel nahezu beliebig einstellen. Es handelt sich dabei um die Eigenschaften RadiusX/RadiusY sowie um Center. Um den damit zu erzielenden optischen Effekt zu sehen, schauen Sie sich bitte die beiden folgenden Abbildungen an, in denen verschiedene Eigenschaftseinstellungen gezeigt werden. #### Die Eigenschaften »RadiusX« und »RadiusY«
    <RadialGradientBrush RadiusX="0" RadiusY="0">
    <RadialGradientBrush RadiusX="0.3" RadiusY="0.3">
    <RadialGradientBrush RadiusX="0.6" RadiusY="0.6">
    <RadialGradientBrush RadiusX="1.0" RadiusY="1.0">
Hier klicken, um das Bild zu vergrößern Abbildung 22.12 Die Auswirkungen der Eigenschaften »RadiusX« und »RadiusY« #### Die Eigenschaft »Center«
    <RadialGradientBrush Center="0.0, 0.0">
    <RadialGradientBrush Center="0.3, 0.3">
    <RadialGradientBrush Center="0.6, 0.6">
    <RadialGradientBrush Center="1.0, 1.0">
Hier klicken, um das Bild zu vergrößern Abbildung 22.13 Die Auswirkungen der Eigenschaft »Center« ### 22.3.4 TileBrush TileBrush ist die abstrakte Basisklasse der drei Klassen DrawingBrush, ImageBrush und VisualBrush. Es bietet sich, zunächst die wesentlichsten Fähigkeiten der Klasse TileBrush zu betrachten, um nachher nur noch einen Blick auf die spezifischen Möglichkeiten der Ableitungen zu werfen. Mit TileBrush wird ein Muster erzeugt, das wiederholt in der Oberfläche angezeigt wird. Das erinnert an Kacheln, wodurch sich auch die Bezeichnung der Klasse erklärt (tile, zu dt. Kachel). Zur Ausgabe mehrerer Kacheln ist zumindest die Angabe der Eigenschaften TileMode und Viewport notwendig. Mit TileMode geben Sie an, ob Sie überhaupt Kacheln anzeigen wollen und in welche Richtung diese verlaufen. Per Vorgabe ist TileMode=Tile eingestellt. Damit werden die Kacheln in horizontaler und vertikaler Richtung auf der Fläche verteilt; mit TileMode=None wird keine Wiederholung des Brushes durchgeführt. Darüber hinaus gibt es mit FlipX, FlipY und FlipXY noch weitere drei Einstellungen. Mit FlipX wird die Brushes-Vorlage entlang der X-Achse gespiegelt, mit FlipY um die Y-Achse. Dass FlipXY gleichzeitig um beide Achsen spiegelt, werden Sie sich nun schon denken können. Viewport dient der Einstellung des Versatzes und der Wiederholungsrate in X- und Y-Richtung. Sehen wir uns das an einem Beispiel an.
    <Canvas Margin="10">
      <Rectangle Height="300" Width="350">
        <Rectangle.Fill>
          <ImageBrush Stretch="Fill" TileMode="Tile" ImageSource="Woman.jpg"
                      Viewport="0, 0, 0.333, 0.5" />
        </Rectangle.Fill>
      </Rectangle>
    </Canvas>
Beim Anwenden eines Brushes auf eine Fläche kann es passieren, dass die Fläche zu klein ist oder nicht ganz ausgefüllt werden kann. Über die Eigenschaft Stretch wird festgelegt, wie der Brush die Fläche ausfüllt. Die TileMode-Eigenschaft ist hier auf Tile eingestellt, sodass Bildwiederholungen möglich sind. Der Eigenschaft Viewport werden vier Zahlen übergeben: Die ersten beiden beschreiben den Versatz, die beiden letzten die Anzahl der Wiederholungen. Letztere beziehen sich auf die Gesamtfläche. Dabei entspricht der Wert 1.0 der Gesamtbreite bzw. -höhe. Mit einer Breitenangabe von 0.333 beträgt die Gesamtbreite einer Kachel 1/3 der zur Verfügung stehenden Gesamtbreite. Analog hat die Höhenangabe 0.5 zur Folge, dass die Höhe einer Kachel 1/2 der Gesamthöhe der Fläche ist. Das Bild wird demnach in der Breite dreimal angezeigt, und in der vertikalen Richtung bilden sich zwei Reihen (siehe Abbildung 22.14). Hier klicken, um das Bild zu vergrößern Abbildung 22.14 Gekacheltes Bild Um den Einfluss des Versatzes zu testen, genügt eine geringe Änderung der an Viewport übermittelten Werte:
    <ImageBrush Stretch="Fill" TileMode="Tile" ImageSource="Woman.jpg"
                Viewport="0.5, 0.33, 0.333, 0.5" />
Die Auswirkungen können Sie in Abbildung 22.15 deutlich sehen. In den Listings wurde die Abmessung einer Kachel abhängig von der Gesamtbreite oder Höhe festgelegt. Soll die einzelne Kachel unabhängig von der Fläche gezeichnet werden, kann die Eigenschaft ViewportUnits auf Absolute gesetzt werden (die Vorgabe ist RelativeToBoundingBox). Dadurch wird es möglich, für die Breite und Höhe einer Kachel absolute Zahlen zu verwenden. Im folgenden Beispiel sind diese auf 120 × 160 Pixel festgelegt.
    ViewportUnits="Absolute" TileMode="Tile" ImageSource="Woman.jpg" Viewport="0,
    0, 120, 160" />
Zwei letzte Eigenschaften sollten an dieser Stelle ebenfalls erwähnt werden. Mit AlignmentX und AlignmentY kann die Startposition der ersten Kachel festgelegt werden. Beide Eigenschaften lassen die Einstellungen Left, Center und Right zu. Hier klicken, um das Bild zu vergrößern Abbildung 22.15 Der Einfluss der Eigenschaft »Viewport« ### 22.3.5 ImageBrush Die Klasse ImageBrush zur Anzeige eines beliebigen Bildes haben wir bereits im letzten Abschnitt benutzt. Der Eigenschaft ImageSource teilen wir die Quelle des Bildes mit. Die Darstellung des Bildes kann mit Stretch beeinflusst werden. Die Eigenschaft ist vom Typ der gleichnamigen Enumeration Stretch, die vier Werte beschreibt.

Tabelle 22.4 Die Werte der Enumeration »Stretch«

Wert | Beschreibung
None | Bei dieser Einstellung bleibt die ursprüngliche Größe des Bildes erhalten.
Fill | Die Größe des Inhalts wird geändert, sodass er die Abmessungen des Ziels ausfüllt. Das Seitenverhältnis wird nicht beibehalten.
Uniform | Die Größe des Bildes passt sich den Abmessungen der Fläche so an, dass es komplett angezeigt wird, ohne dass das Seitenverhältnis verändert wird.
UniformToFill | Die Größe des Bildes passt sich den Abmessungen der Fläche so an, dass es die Fläche komplett ausgefüllt wird, ohne dass das Seitenverhältnis des Bildes dabei verändert wird.
Wie sich die Einstellungen auf die Darstellung eines Bildes auswirken, zeigt Abbildung 22.16. Hier klicken, um das Bild zu vergrößern Abbildung 22.16 Der Einfluss der Eigenschaft »Stretch« ### 22.3.6 VisualBrush VisualBrush dürfte wohl das leistungsfähigste aller Brush-Elemente sein. Zur Füllung dienen VisualBrush alle die Elemente, die von Visual abgeleitet sind. Dazu gehören demnach neben Buttons und TextBoxen auch Bilder vom Typ Image. Prinzipiell können Sie auf zwei Weisen den Inhalt eines VisualBrush-Elements erstellen: Sie weisen der Eigenschaft Visual ein neues Element zu. Sie verwenden ein bereits vorhandenes Element. Mit VisualBrush lassen sich tolle Effekte erzielen. Hierbei kommen Eigenschaften ins Spiel, die wir bereits vorher angesprochen haben: Stretch, Opacity, Viewport und TileMode. Sie werden aber auch Eigenschaften finden wie Transform und RelativeTransform. Transformationen sind ein mächtiges Werkzeug der WPF und werden dazu verwendet, geometrische Objekte und UI-Komponenten zu manipulieren. Das heißt, Sie können geometrische Objekte drehen, sie rotieren lassen, sie skalieren oder gar scheren. Das Zusammenspiel von VisualBrush und Transformationen soll das folgende Beispielprogramm demonstrieren. Bevor wir uns dem XAML-Code widmen, sehen wir uns die Ausgabe des Beispielprogramms an. Hier klicken, um das Bild zu vergrößern Abbildung 22.17 Ausgabe des Beispielprogramms »VisualBrushSample«
    // ---------------------------------------------------------
    // Beispiel: ...\Kapitel 22\VisualBrushSample
    // ---------------------------------------------------------
    <Window ...
            Title="VisualBrushSample" Height="300" Width="400">
      <Grid>
        <StackPanel>
          <StackPanel.Background>
            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
              <GradientStop Offset="0.0" Color="Black" />
              <GradientStop Offset="1.0" Color="Gray" />
            </LinearGradientBrush>
          </StackPanel.Background>
          <Image Margin="0,10,0,0" Source="Jeepney.jpg" Name="Jeepney"
                 Height="150" Width="200" Stretch="Uniform" />
          <Rectangle Height="80">
            <Rectangle.Fill>
              <VisualBrush Visual="{Binding ElementName=Jeepney}"
                           Stretch="None" Opacity="0.6">
                <VisualBrush.RelativeTransform>
                  <TransformGroup>
                    <ScaleTransform ScaleY="-1.5" />
                    <TranslateTransform Y="1" />
                    <SkewTransform AngleX="-12" />
                  </TransformGroup>
                </VisualBrush.RelativeTransform>
              </VisualBrush>
            </Rectangle.Fill>
          </Rectangle>
        </StackPanel>
      </Grid>
    </Window>
Irgendwo im XAML-Code muss die Komponente, die mit Effekten versehen werden soll, bereits definiert sein. In unserem Beispiel handelt es sich um das durch ein Image-Element beschriebene Bildchen. Die Eigenschaft Visual des VisualBrush-Elements wird an das Image gebunden und steht somit für effektvolle Manipulationen zur Verfügung. Gleichzeitig wird die Transparenz mit der Eigenschaft Opacity auf 60 % festgelegt. Mit RelativeTransform leiten wir die Transformation mit relativen Koordinaten ein. Eine Transformation kann sich aus mehreren Einzeleffekten zusammensetzen. Um diese zusammenzufassen, wird ein TransformGroup-Element benötigt. Dieses fasst mehrere Elemente zusammen, deren Basis die Klasse Transform ist. Dazu gehören auch die Elemente TranslateTransform, ScaleTransform und SkewTransform. ScaleTransform skaliert das visuelle Element, TranslateTransform verschiebt es, und SkewTransform beschreibt einen Neigungswinkel. ### 22.3.7 DrawingBrush Das letzte Brush-Objekt, über das ich noch viele Worte verlieren könnte, ist DrawingBrush. DrawingBrush verwendet zum Füllen der Kacheln Grafiken. Man kann erheblichen Einfluss auf die Zeichnung nehmen – es bleiben fast keine Wünsche offen. Der Inhalt selbst wird durch ein Drawing-Objekt beschrieben, das der gleichnamigen Eigenschaft zugewiesen wird. Mit DrawingGroup, GeometryDrawing, GlyphRunDrawing, ImageDrawing und VideoDrawing stehen gleich fünf verschiedene Drawing-Objekte zur Verfügung.