MSDN Magazin > Home > Ausgaben > 2007 > May >  WPF: Anpassen von Steuerelementen für Wind...
WPF
Anpassen von Steuerelementen für Windows Presentation Foundation
Shawn Wildermuth

Themen in diesem Artikel:
  • Zusammengesetzte Steuerelemente
  • Stile und Vorlagen
  • Benutzerdefinierte Eigenschaften
  • Benutzerdefinierte Steuerelemente
In diesem Artikel werden folgende Technologien verwendet:
Windows Presentation Foundation
Das Steuermodell in Windows Presentation Foundation ist erstaunlich vielfältig, es ist jedoch unmöglich, jedes einzelne Steuerelement bereitzustellen, das Sie eventuell benötigen. Hier kommt die Steuerelementerstellung zur Hilfe. In diesem Artikel erfahren Sie, wie vorhandene Steuerelemente mithilfe von Windows® Presentation Foundation angepasst werden und wie Sie völlig neue Steuerelemente für Ihre Projekte erstellen.
Bevor Sie ein benutzerdefiniertes Steuerelement entwickeln, müssen Sie sich genau überlegen, ob sie es auch wirklich brauchen. In Windows Presentation Foundation können Sie mithilfe von Gestaltung, Stilen und Vorlagen vorhandene Steuerelemente in solch einem Ausmaß anpassen, wie es mit vergangenen Technologien nicht möglich war. Bevor Sie sich dafür entscheiden, ein neues Steuerelement zu erstellen, betrachten Sie diese drei Methoden zum Anpassen von Steuerelementen.

Verwenden der Gestaltung
Eine häufige Anforderung ist die Erstellung eines zusammengesetzten Steuerelements, d. h. eines Steuerelements, das aus mehreren Steuerelementen besteht. Angenommen, es geht um die Schaltfläche „Wiedergabe“, um die Wiedergabe eines Videos zu starten. XAML und das Steuerelement werden in Abbildung 1 dargestellt.
<StackPanel>
  <Button Height=”50” Width=”50” Content=”Play” />
  <Polygon HorizontalAlignment=”Center” 
           Points=”0,0 0,26 17,13”
           Fill=”Black” />
</StackPanel>
Sie müssen das Wiedergabesymbol auf die Schaltfläche setzen können. Sie können die Gestaltung dazu verwenden, XAML-Elemente innerhalb von anderen XAML-Elementen einzubetten. Zum Beispiel können Sie die XAML ändern, um die Bezeichnung und das Symbol als den Inhalt der Schaltfläche zu erstellen. Wie in Abbildung 2 dargestellt, werden diese Elemente dadurch, dass sie innerhalb eines Containers (in diesem Fall StackPanel) in der Schaltfläche platziert werden, der Content-Eigenschaft zugeordnet. Das Ergebnis ist eine Schaltfläche, die so wie andere Schaltflächen funktioniert, aber Ihren Inhalt enthält.
<StackPanel>
  <Button Height=”50” Width=”50”>
    <StackPanel>
      <TextBlock>Play</TextBlock>
      <Polygon Points=”0,0 0,26 17,13”
               Fill=”Black” />
    </StackPanel>
  </Button>
</StackPanel>
Das Verwenden der Gestaltung zum Erstellen von solchen Steuerelementen ist einfach. Im Gegensatz zu Präsentationstechnologien, wie Windows Forms, Visual Basic® 6.0 und MFC, sind die meisten Steuerelemente Container für andere Steuerelemente. Es ist nicht nötig, ein benutzerdefiniertes Steuerelement zu erstellen, wenn Sie lediglich ein zusammengesetztes Steuerelement benötigen.

Verwenden von Stilen
Was ist der Ansatz, wenn nur die Darstellung des Steuerelements geändert werden soll? Stile lautet die Antwort. Sie können einen Schaltflächenstil angeben, der einen roten Rahmen hat, indem Sie einen Stil wie diesen erstellen.
<StackPanel>
  <StackPanel.Resources>
    <Style TargetType=”Button” x:Key=”RedButton”>
      <Setter Property=”BorderBrush” Value=”Red” />
    </Style>
  </StackPanel.Resources>
  ...
</StackPanel>
Jetzt können Sie den Rahmen bestimmter Schaltflächen ändern, indem Sie ihnen einen Stil zuordnen, wie in Abbildung 3 dargestellt. Die erste Schaltfläche ist die Standarddarstellung, während die zweite mit einem freigegebenen Stil verknüpft ist.
Abbildung 3
<Button Height=”50” Width=”50”>
  <StackPanel>
    <TextBlock>Play</TextBlock>
    <Polygon Points=”0,0 0,26 17,13”
             Fill=”Black” />
  </StackPanel>
</Button>
<Button Height=”50” Width=”50” Style=”{StaticResource RedButton}”>
  <StackPanel>
    <TextBlock>Play</TextBlock>
    <Polygon Points=”0,0 0,26 17,13”
             Fill=”Black” />
  </StackPanel>
</Button>
Sie können mithilfe von Stilen sogar die Darstellung aller Instanzen eines bestimmten XAML-Elements containerübergreifend ändern. Anstatt zum Beispiel einen wiederverwendbaren Stil zu erstellen, um die Schaltfläche zu ändern, können Sie einen Stil erstellen, der das Aussehen aller Schaltflächen festlegt, wie in Abbildung 4 dargestellt. In diesem Beispiel wird der Hintergrund aller Schaltflächen auf den Farbverlauf Grau/Grün/Grau festgelegt. Der Stil in diesem Beispiel unterdrückt den Schlüssel des Stils. Das führt dazu, dass alle Elemente betroffen sind, die im TargetType-Attribut angegeben sind.
Abbildung 4
<StackPanel>
  <StackPanel.Resources>

    <Style TargetType=”Button”>
      <Setter Property=”Background”>
        <Setter.Value>
          <LinearGradientBrush>
            <GradientStop Color=”#DDDDDD” Offset=”0” />
            <GradientStop Color=”#88FF88” Offset=”.6” />
            <GradientStop Color=”#EEEEEE” Offset=”1” />
          </LinearGradientBrush>
        </Setter.Value>
      </Setter>
    </Style>

  </StackPanel.Resources>

  <Button Height=”50” Width=”50”>
    <StackPanel>
      <TextBlock>Play</TextBlock>
      <Polygon Points=”0,0 0,26 17,13”
               Fill=”Black” />
    </StackPanel>
  </Button>

  <Button Height=”50” Width=”50”>
    <StackPanel>
      <TextBlock>Play</TextBlock>
      <Polygon Points=”0,0 0,26 17,13”
               Fill=”Black” />
    </StackPanel>
  </Button>

</StackPanel>

Verwenden von Vorlagen
Stile können nur die Standardeigenschaften in XAML-Elementen festlegen. Wenn z. B. in den früheren Beispielen BorderBrush festgelegt wurde, konnte zwar der Pinsel, nicht jedoch die Breite des Rahmens angegeben werden. Für eine völlig freie Darstellung eines Steuerelements müssen Sie Vorlagen verwenden. Dafür erstellen Sie einen Stil und geben die Template-Eigenschaft an (siehe Abbildung 5). Der Wert der Template-Eigenschaft wird zu einem ControlTemplate-Element, das angibt, wie das Steuerelement selbst erstellt werden soll. In diesem Beispiel wird eine Schaltfläche folgendermaßen angegeben: als ein Kreis mit dem Wiedergabesymbol in der Mitte. Dies wird durch das Schichten des Wiedergabesymbols über ein Ellipse-Element erreicht. Die neue Vorlagenschaltfläche wird neben einer normalen Schaltfläche angezeigt.
Abbildung 5
<StackPanel>
  <StackPanel.Resources>

    <Style TargetType=”{x:Type Button}” x:Key=”PlayButton” >
      <Setter Property=”Template”>
        <Setter.Value>
          <ControlTemplate TargetType=”{x:Type Button}”>
            <Grid>
              <Ellipse Width=”{TemplateBinding Width}”
                       Height=”{TemplateBinding Height}”
                       Stroke=”DarkGray”
                       VerticalAlignment=”Top”
                       HorizontalAlignment=”Left”
                       Fill=”LightGray” />
              <Polygon Points=”18,12 18,38 35,25”
                       Fill=”Black” />
            </Grid>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

  </StackPanel.Resources>

  <Button Height=”50” Width=”50”>Normal Button</Button>
  <Button Height=”50” Width=”50” Style=”{StaticResource PlayButton}” />

</StackPanel>
Letzten Endes ermöglichen die Stile und die Vorlagen nur das Ändern der Steuerelementdarstellung. Um Verhalten und andere Features zur Schaltfläche hinzuzufügen, werden Sie ein benutzerdefiniertes Steuerelement erstellen müssen.

Erstellen von Steuerelementen
Vor dem Erstellen Ihres eigenen Steuerelements müssen Sie als Erstes entscheiden, welche Methode Sie zum Erstellen des Steuerelements verwenden. Es gibt hauptsächlich zwei Möglichkeiten, Steuerelemente in Windows Presentation Foundation zu erstellen: Benutzersteuerelemente und benutzerdefinierte Steuerelemente. Beide Methoden haben ihre Vorteile.
Mit Benutzersteuerelementen rufen Sie ein einfaches Entwicklungsmodell ab, das der WPF-Anwendungsentwicklung ähnlich ist. Benutzersteuerelementen wird der Vorzug gegeben, wenn Sie ein Steuerelement aus vorhandenen Komponenten verfassen müssen und wenn keine komplizierte Anpassung (wie bei Vorlagen und Stilen) erforderlich ist. Benutzerdefinierte Steuerelemente sind die bessere Wahl, wenn Sie eine vollständige Kontrolle über die Darstellung oder einen besonderen Renderingsupport erfordern, oder wenn Sie möchten, dass Ihr Steuerelement ein Container für andere Steuerelemente ist.
Wenn Sie sich nicht entscheiden können, welche Art von Steuerelement Sie nehmen sollen, wählen Sie ein Benutzersteuerelement. Wenn Sie mit einem Benutzersteuerelement nicht mehr weiterkommen, können Sie später relativ problemlos auf benutzerdefinierte Steuerelemente umsatteln.
Als Erstes müssen Sie beim Erstellen eines Benutzersteuerelements Ihrem Projekt ein neues Element hinzufügen. Wenn Sie mit der rechten Maustaste auf Ihr Projekt klicken und auf „Hinzufügen“ klicken, kann es sehr verlockend sein, im Kontextmenü die Option „Benutzersteuerelement“ zu wählen. Leider startet dieser Vorgang den Versuch, ein neues Windows Forms-Benutzersteuerelement zu erstellen. Wählen Sie stattdessen die Option „Neues Element hinzufügen“. Wählen Sie im Dialogfeld „Neues Element hinzufügen“ die Option „Benutzersteuerelement (WPF)“ aus.
Beim Erstellen des neuen Benutzersteuerelements wird eine neue XAML-Datei und eine Sicherheitscodedatei erstellt. Die XAML-Datei ist so ähnlich wie die Hauptdatei, die mit neuen Windows Presentation Foundation-Projekten erstellt wird. Der Unterschied liegt darin, dass das Stammelement der neuen XAML-Datei ein UserControl-Element ist. Innerhalb des UserControl-Elements erstellen Sie den Inhalt, der Ihr Steuerelement verfasst.
Fahren Sie bei diesem Beispiel mit der gleichen XAML fort, die zuvor zum Erstellen einer Vorlage für ein PlayButton-Steuerelement verwendet wurde. Dieses neue Steuerelement verknüpft sich mit einem MediaElement, um die Wiedergabe oder das Anhalten einiger digitaler Medien zu steuern. Abbildung 6 stellt die XAML-Datei von PlayButton dar.
Abbildung 7 PlayButton in einem WPF-Fenster 
<!-- PlayButton.xaml --> 
<UserControl x:Class=”CustomWPF.PlayButton”
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”>

  <Grid>

    <Ellipse Width=”50” Height=”50” 
             Stroke=”DarkGray”
             VerticalAlignment=”Top”
             HorizontalAlignment=”Left”
             Name=”ButtonBack”                       
             Fill=”LightGray” />
    <Path Name=”PlayIcon” Fill=”Black”
          Data=”M18,12 18,38 35,25”/>
    <Path Name=”PauseIcon” Fill=”Black” Opacity=”0”
          Data=”M15,12 15,38 23,38 23,12z M27,12 27,38 35,38 35,12” />

  </Grid>

</UserControl>
Vom Vorlagenbeispiel wurde hier ein neuer Pfad, PauseIcon, hinzugefügt. Da das Symbol für das Anhalten der Medien nicht als ein Polygon dargestellt werden konnte, war es einfacher, PlayIcon zu einem Pfad zu ändern, sodass jedes Symbol als ein Pfadobjekt im Codebehind behandelt werden kann. Das Ziel hierbei ist, ein MediaElement-Element durch Anhalten oder Wiedergeben der Medien zu kontrollieren, wenn auf die Schaltfläche geklickt wird. Außerdem soll das Symbol so geändert werden, dass es die Aktion (Pause oder Wiedergabe) korrekt darstellt, wenn auf die Schaltfläche geklickt wird.
Vor dem Hinzufügen dieser Logik soll sichergestellt werden, dass die Schaltfläche richtig angezeigt wird und dass sie in einem Fenster angezeigt werden kann. In diesem Fall soll das neue Steuerelement in einem Fenster angezeigt werden. Bevor Sie ein beliebiges benutzerdefiniertes Element (Benutzersteuerelement oder benutzerdefiniertes Steuerelement) in einem XAML-Dokument verwenden können, müssen Sie einen Verweis dazu erstellen. Wenn das benutzerdefinierte Element sich im gleichen Projekt befindet wie der Rest Ihrer XAML, können Sie darauf einfach durch Hinzufügen einer XML-Namespacedeklaration verweisen. In den folgenden Codezeilen wurde eine Namespacedeklaration (xmlns:cust) erstellt, das einen Namespace für die gemeinsame Sprachlaufzeit (CLR) erstellt, in dem sich das Steuerelement befindet.
<!-- MainWindow.xaml -->
<Window x:Class=”Tester.MainWindow”
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
    xmlns:cust=”clr-namespace:CustomWPF“
    Title=”Control Viewer” 
    Height=”100” Width=”200”>

  <!-- ... -->

</Window>
Der clr-Namespace (CustomWPF), der in der XML-Namespacedeklaration angegeben ist, stimmt mit dem eigentlichen CLR-Namespace des Steuerelements (CustomWPF) überein. Wenn das Steuerelement, das Sie verwenden möchten, in einer anderen Assembly enthalten ist, müssen Sie in der Namespacedeklaration auch den Assemblynamen vermerken. Die XML-Namespacedeklaration importiert die Assembly nicht automatisch in Ihr Projekt. Sie müssen dazu Ihrem Projekt manuell einen Assemblyverweis hinzufügen.
<!-- MainWindow.xaml -->
<Window x:Class=”Tester.MainWindow”
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
    xmlns:cust=”clr-namespace:CustomWPF;assembly=CustomWPF”
    Title=”Control Viewer” 
    Height=”100” Width=”200”>

  <!-- ... -->

</Window>
Sobald der Verweis zum XML-Namespace erfolgt ist, können Sie damit Instanzen von Ihrem neuen Benutzersteuerelement erstellen. Dies erfolgt mithilfe des Namens der Namespacedeklaration. Damit ist das XML-Namespacealias gemeint, nicht der CLR-Namespace. Nach dem XML-Namespacealias muss der eigentliche Name des Steuerelements angegeben werden. Dies stellt sichert, dass der Name, der in der XAML-Datei verwendet wird, mit dem Namen der Klasse übereinstimmt. Zum Hinzufügen einer Instanz der PlayButton-Klasse zur XAML muss als Elementname cust:PlayButton angegeben werden.
<StackPanel>
  <TextBlock HorizontalAlignment=”Center”>User Control:</TextBlock>
  <cust:PlayButton />
</StackPanel>
Jetzt können Sie das PlayButton-Steuerelement sehen, das in einem typischen Fenster von Windows Presentation Foundation gehostet wird, wie in Abbildung 7 dargestellt.

Benutzerdefinierte Eigenschaften
Beim Erstellen von Steuerelementen ist es oft nötig, Eigenschaften zu implementieren, um sowohl die Darstellung des Steuerelements als auch sein Laufzeitverhalten zu verwalten. Zum Beispiel muss das PlayButton-Steuerelement in der Lage sein, die Farbe des Symbols abzurufen und festzulegen. Dazu können Sie eine einfache CLR-Eigenschaft erstellen, wie in Abbildung 8 dargestellt. (Beachten Sie, dass ein Visual Basic-Beispielcode im Download für diesen Artikel verfügbar ist.)
// PlayButton.xaml.cs
public partial class PlayButton : System.Windows.Controls.UserControl
{
  // ...

  Brush _iconColor = Brushes.Black;

  public Brush IconColor
  {
    get {return _iconColor; }
    set
    {
      _iconColor = value;
      PlayIcon.Fill = _iconColor;
      PauseIcon.Fill = _iconColor;
    }
  }
}
Einfache CLR-Eigenschaften wie die IconColor-Eigenschaft funktionieren ziemlich gut. Sie können sie in der XAML-Datei einfach mithilfe des Namens der Eigenschaft festlegen:
<cust:PlayButton IconColor=”Black” />
Einfache Eigenschaften sind für die meisten Steuerelemente jedoch nicht ausreichend, weil sie erweiterte Features, wie Datenbindung oder Animationssupport, nicht unterstützen. Wenn Sie zum Beispiel die IconColor Ihres Steuerelements durch Datenbindung mit der Füllbereichfarbe eines Rechtecks in der XAML-Datei angeben möchten, funktioniert dies nicht, wie Sie in Abbildung 9 sehen können.
<!-- MainWindow.xaml -->
<Window x:Class=”Tester.MainWindow”
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
    xmlns:cust=”clr-namespace:CustomWPF;assembly=CustomWPF”
    Title=”Control Viewer” 
    Height=”100” Width=”200”>

  <StackPanel>
    <Rectangle Name=”theRect” Fill=”Red” />
    <TextBlock>User Control:</TextBlock>

    <!-- Simple Assignment Works -->
    <cust:PlayButton IconColor=”Blue” />

    <!—Data Binding Does Not -->
    <cust:PlayButton 
      IconColor=”{Binding ElementName=theRect, Path=Fill}” />

  </StackPanel>
</Window>
Um alle verfügbaren Features auszunutzen, müssen Sie eine Abhängigkeitseigenschaft (DependencyProperty) statt einer einfachen CLR-Eigenschaft verwenden. Abhängigkeitseigenschaften ermöglichen, dass der Wert eines Elements durch verschiedene Mittel festgelegt werden kann, einschließlich Animationen und Datenbindung. Um eine Eigenschaft zu implementieren, erstellen Sie ein statisches DependencyProperty-Feld (freigegeben in Visual Basic) im Steuerelement, indem Sie die DependencyProperty.Register-Methode aufrufen. Diese Methode registriert Ihre Eigenschaft und gibt eine Instanz der erstellten DependencyProperty zurück.
Nachdem das DependencyProperty-Feld erstellt ist, können Sie damit die Eigenschaft mithilfe der GetValue/SetValue-Methoden Ihres Steuerelements festlegen und abrufen. Zum Beispiel können Sie die IconColor-Eigenschaft von PlayButton zu einer DependencyProperty ändern, wie in Abbildung 10 dargestellt.
Beachten Sie, dass das Feld „Pinsel“ von der Klasse entfernt wurde. Die DependencyProperty speichert den Wert für jede Instanz sowie die Metadaten über die Eigenschaft. Das heißt, dass nicht jede Instanz von PlayButton über ein eigenes Feld verfügen muss, um die Daten über die Eigenschaft zu speichern.
Nachdem jetzt eine DependencyProperty vorhanden ist, können Sie sie in der Datenbindung oder Animation verwenden. Derzeit gibt es keine gute Möglichkeit, um zu bestimmen, ob sich die Eigenschaft geändert hat, und es gibt auch keinen Standardwert. Da das Festlegen des Eigenschaftswerts nicht durch die öffentliche Eigenschaft weitergeleitet wird (die CLR-Eigenschaft ist eine Verpackung für die DependencyProperty, nicht umgekehrt), ist es nicht möglich, einfach den Accessor „Set“ zu verwenden, um die Symbolfarbe zu ändern, wenn dieser Wert geändert wird. Sie müssen ein Ereignis hinzufügen, das aufgerufen wird, wenn sich die Eigenschaft ändert. Geben Sie dafür eine statische oder freigegebene Methode an, die zurückgerufen werden kann, wenn die Eigenschaft sich beim Registrieren der DependencyProperty ändert. Sie können die Registrierung so ergänzen, dass sie ein FrameworkPropertyMetadata-Objekt umfasst, das sowohl den Standardwert als auch einen Änderungsrückruf angibt, wie hier dargestellt:
public static readonly DependencyProperty IconColorProperty =
        DependencyProperty.Register(
            “IconColor”, 
            typeof(Brush), 
    typeof(PlayButton),
    new FrameworkPropertyMetadata(Brushes.Black,
    new PropertyChangedCallback(OnIconColorChanged
    )));
Abschließend müssen Sie den Rückruf implementieren. Dieser Rückruf ist eine statische (oder freigegebene) Methode Ihres Steuerelements, die das geänderte Objekt und die Argumente, die die alten und neuen Werte angeben, annimmt. In der Regel würden Sie eine Methode für das geänderte Objekt aufrufen, um es zu aktualisieren. Wenn zum Beispiel die IconColor geändert wurde, werden Sie vermutlich den Füllbereich für beide Symbole festlegen wollen. Im Folgenden werden sowohl die Rückrufmethode als auch die Updatemethode gezeigt:
private static void OnIconColorChanged(DependencyObject obj,
    DependencyPropertyChangedEventArgs args)
{
  // When the color changes, set the icon color
  PlayButton control = (PlayButton)obj;
  control.PlayIcon.Fill = control.IconColor;
  control.PauseIcon.Fill = control.IconColor;
}
Um das Steuerelement abzuschließen, ist außerdem eine DependencyProperty wünschenswert, um das Zuordnen von MediaElement zum Steuerelement zu ermöglichen (siehe Abbildung 11).
Nachdem jetzt die Eigenschaft vorliegt, können Sie der XAML-Datei MediaElement hinzufügen und dieses Element durch Datenbindung an die neue MediaPlayer-Eigenschaft binden. Wenn Sie der XAML das MediaElement hinzufügen, müssen Sie LoadedBehavior auf „Manuell“ festlegen, wodurch Sie die Wiedergabe manuell kontrollieren können. Die neue XAML-Datei wird in Abbildung 12 dargestellt.
<!-- MainWindow.xaml -->
<Window x:Class=”Tester.MainWindow”
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
    xmlns:cust=”clr-namespace:CustomWPF;assembly=CustomWPF”
    Title=”Control Viewer” 
    Height=”100” Width=”200”>
  <StackPanel>

    <MediaElement Width=”150” Height=”100” 
         Name=”theMedia” 
         Source=”http://download.microsoft.com/.../ctorrec9billg.wmv”
         LoadedBehavior=”Manual” />

    <TextBlock>User Control:</TextBlock>

    <cust:PlayButton MediaPlayer=”{Binding ElementName=theMedia}” />

  </StackPanel>
</Window>
Als Nächstes implementieren Sie ein Klickereignis im PlayButton-Benutzersteuerelement. Fügen Sie zuerst dem Hauptraster des Steuerelements ein MouseLeftButtonUp-Ereignis hinzu.
<!-- PlayButton.xaml --> 
<UserControl x:Class=”CustomWPF.PlayButton”    
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”>
  <Grid MouseLeftButtonUp=”PlayButton_Clicked”>
    <!-- ... -->
  </Grid>
</UserControl>
Dadurch können Sie das Verhalten des Steuerelements implementieren und das Symbol ändern. Diese Implementierung des Ereignishandlers ist in Abbildung 13 dargestellt. Das abgeschlossene Steuerelement und das Video sind in Abbildung 14 zu sehen.
Abbildung 14 Abgeschlossenes Benutzersteuerelement 
Benutzerdefinierte Steuerelemente
Das PlayButton-Steuerelement, das Sie eben erstellt haben, funktioniert recht gut, doch ihm fehlt der vollständige Support für Vorlagen und Designs. Wenn Ihr Steuerelement diesen Support braucht, werden Sie es als ein benutzerdefiniertes Steuerelement erstellen müssen. Benutzerdefinierte Steuerelemente leiten sich von anderen Klassen in der Hierarchie der Steuerelemente ab. Zum Beispiel können Sie das PlayButton-Steuerelement in ein MediaButton-Steuerelement umwandeln, das mehr Möglichkeiten zur Wiederverwendung bietet.
Zum Erstellen eines MediaButton-Steuerelements wählen Sie zuerst „Benutzerdefiniertes Steuerelement (WPF)“ im Visual Studio-Dialogfeld „Neues Element hinzufügen“ aus. Dadurch wird dem Projekt eine neue Datei für die benutzerdefinierte Steuerelementklasse (MediaButton.cs) und außerdem ein Designordner mit einer generic.xaml-Datei hinzugefügt. Die generic.xaml-Datei enthält eine Vorlage für die neue Steuerelementklasse. Diese XAML-Datei wird dazu verwendet, verschiedene Designs für das Steuerelement zu ermöglichen. Die generic.xaml-Datei wird als ein Fallback verwendet. Für die meisten Steuerelemente ist dies die einzige Designdatei, die erstellt wird. Wenn Sie ein Steuerelement erstellen wollen, das seine Darstellung je nach aktuellem Design ändert, können Sie in diesem Verzeichnis Designdateien erstellen. Abbildung 15 stellt die Standarddesigndateien dar und zeigt, wann sie verwendet werden.
Durch die Angabe mehrerer Designs können Sie die Darstellung Ihrer Steuerelemente entsprechend der Designauswahl des Benutzers ändern. Um ein generisches Design für das vorliegende Beispielsteuerelement zu entwickeln, kann die XAML-Datei des Benutzersteuerelements innerhalb des ControlTemplate-Tags platziert werden. Nachdem sich die XAML in der Vorlage befindet, empfiehlt sich die Verwendung der Vorlagenbindung, um die Eigenschaften der XAML entsprechend den Eigenschaften des Steuerelements festzulegen. Bisher wurde die Breite und Höhe von PlayButton immer auf fünfzig logische Einheiten festgelegt. Für ein einfaches Steuerelement ist dies nachvollziehbar. Wenn Sie jedoch wirklich ein wiederverwendbares Steuerelement haben möchten, sollten Sie die Vorlage wiederverwendbar machen. Dafür müssen Sie die Höhe und Breite der Vorlage durch die Höhe und Breite des Steuerelements ersetzen, indem Sie die Höhe und Breite in der Vorlage als {TemplateBinding Width} und {TemplateBinding Height} markieren.
Im PlayButton ändern Sie einfach die Durchlässigkeit der beiden Symbole, je nachdem, ob die Schaltfläche Wiedergabe oder Pause anzeigen muss. Tief in die Vorlage vorzudringen, um die Undurchsichtigkeit zu ändern, würde zwar funktionieren, wäre jedoch ziemlich umständlich. Eine bessere Lösung ist es, ein Pfadobjekt mit einem einzigen Symbol zu verwenden und die Zeichnungsdaten zu ändern, sodass das richtige Symbol gezeichnet wird. Auf diese Weise beeinflusst die Größe der visuellen Struktur direkt die Leistung des XAML-Dokuments. Damit dies funktioniert, führen Sie eine neue DependencyProperty ein, um das aktuelle Symbol, das verwendet werden soll, zu speichern. Erstellen Sie eine Enumeration, die angibt, welches Symbol verwendet werden soll, und machen Sie sie als eine DependencyProperty zugänglich. Mit der neuen Icon-Eigenschaft können Sie die Vorlage so ändern, dass sie für den Fall, dass sich die Icon-Eigenschaft ändert, Trigger enthält.
Das Symbol verwendet ein Pfadelement, um die Darstellung der einzelnen Symbole zu definieren, die von der Schaltfläche verwendet werden. Dies funktioniert gut, wenn die Schaltfläche immer dieselbe Größe hat. Da dies jedoch nicht der Fall ist, müssen Sie eine Möglichkeit finden, um die Größe des Symbols mit der Schaltfläche zu ändern. Eine Lösung besteht darin, eine sich überlagernde Ellipse über dem Hintergrundkreis zu erstellen und ein VisualBrush zu verwenden, um das Symbol zu platzieren. Der VisualBrush ermöglicht die Größenanpassung des Hintergrunds mit dem Steuerelement. Die abgeschlossene generic.xaml-Vorlage ist in Abbildung 16 dargestellt.
Dieser MediaButton soll, so wie der PlayButton, ein Medienelement kontrollieren. Kopieren Sie die MediaPlayer-DependencyProperty vom PlayButton zum MediaButton. Stellen Sie sicher, dass Sie beliebige Verweise im kopierten Code von PlayButton zu MediaButton ändern (besonders in der DependencyProperty-Registrierung).
Im Unterschied zu PlayButton müssen Sie das Mausklickereignis in der Vorlage nicht behandeln. Stattdessen können Sie das Ereignis On­Mouse­Left­But­tonUp außer Kraft setzen, damit es auf Klicks reagiert. Innerhalb dieser Methode können Sie das Symbol ändern und Medien wiedergeben oder anhalten. Der endgültige Code des benutzerdefinierten Steuerelements ist in Abbildung 17 dargestellt. Nachdem das neue Steuerelement jetzt die Größenanpassung und das Einrichten der Icon-Eigenschaft unterstützt, können Sie Benutzern mehr Flexibilität beim Ändern der Größe und des Symbols des Steuerelements bieten. Abbildung 18 stellt das Steuerelement mit verschiedenen Größen und Symbolen dar.
Abbildung 18 Alle Formen und Größen  

In diesem Steuerbeispiel wurde direkt von der Klasse System.Windows.Con­trols.Control abgeleitet. Doch so, wie benutzerdefinierte Steuerelemente aufgebaut sind, kann von einer beliebigen Stelle in der Klassenhierarchie abgeleitet werden. Sie können benutzerdefinierte Steuerelemente verwenden, um das Verhalten eingebauter Steuerelemente außer Kraft zu setzen und zu ändern oder um Ihre eigenen Steuerelemente ganz neu zu erstellen. Beispielsweise würde das Ableiten von FrameworkElement es ermöglichen, ein Steuerelement mit nur wenigen eingebauten Layoutmechanismen zu erstellen. Das Ableiten vom Fensterbereich ermöglicht Ihnen das Erstellen Ihrer eigenen spezialisierten Container für andere Objekte. Es ist nicht einfach, die richtige Klasse für das Ableiten zu bestimmen. Dies hängt von den Anforderungen Ihres Steuerelements ab.

Schlussbemerkung
Wenn Sie eine spezielle Steuerfunktionalität benötigen, haben Sie mehrere Optionen, einschließlich Gestaltung, Stile und Vorlagen. Mithilfe der Aufteilung in Komponenten können Sie häufig zusammengesetzte Steuerelemente erstellen, wodurch das Verfassen eines neuen Steuerelements vermieden wird. Wenn nur die Darstellung eines Steuerelements geändert werden muss, verwenden Sie Stile. Abschließend ist anzumerken, dass Vorlagen eine vollständige Kontrolle über die Gestaltung eines vorhandenen Steuerelements gewähren. Weitere Informationen zum Verwenden von Vorlagen für die Anpassung von Steuerelementen finden Sie in der Foundations-Rubrik von Charles Petzold.
Wenn Sie sich dafür entscheiden, ein neues Steuerelement zu verfassen, werden Sie nach wie vor das vereinfachte Programmiermodell abrufen, bei dem Sie das Gefühl haben, als ob Sie Ihr eigenes Fenster oder Ihre eigene Seite schreiben. Benutzerdefinierte Steuerelemente haben den wesentlichen Vorteil, dass sie Ihnen das Erstellen von Vorlagen für Ihre Steuerelemente ermöglichen, die in den Designs der verschiedenen Betriebssysteme jeweils anders aussehen und sich sogar anders verhalten.
Ein vorhandenes Benutzersteuerelement zu einem benutzerdefinierten Steuerelement zu wechseln, ist nicht besonders schwierig. Da Sie jedoch mit einer Vorlage, und nicht mit einem Direktzugriff auf XAML-Objekte, arbeiten, werden Sie die Weise, wie Sie Ihr benutzerdefiniertes Steuerelement konstruieren, ändern müssen.
Bei Windows Presentation Foundation ist die Notwendigkeit für das Schreiben benutzerdefinierter Steuerelemente eher die Ausnahme und nicht die Regel. Nur dann, wenn Sie wirklich ein benutzerdefiniertes Verhalten erstellen, wird es nötig, sich mit der Steuerelementerstellung zu befassen. Weitere Informationen zu Steuerelementen in Windows Presentation Foundation finden Sie im SDK unter msdn2.microsoft.com/ms754130.aspx.

Shawn Wildermuth ist ein Microsoft MVP, MCSD.NET, MCT und der Gründer von Wildermuth Consulting Services. Shawn hat außerdem Pragmatic ADO.NET (Addison-Wesley, 2002) verfasst und ist der Mitautor von vier Microsoft-Zertifizierungslehrgängen sowie von „Prescriptive Data Architectures“. Er kann über seine Website www.wildermuthconsulting.com kontaktiert werden.

Page view tracker