Seiten

Dienstag, 16. November 2010

How to: Erstellen eines nicht rechteckigen ChildWindow - Teil 1

Dieser Artikel beschreibt Schritt-für-Schritt, wie man ein nicht rechteckiges ChildWindow erstellt. Erstellt wird ein ringförmiges ChildWindow.

Als Vorgeschmack auf das, was wir in diesem Tutorial zusammenbauen wollen, gibt es hier schonmal einen Blick auf die fertige Beispiel-Anwendung:


Ziemlich cool, oder?! Den Link für den Download des obigen Beispiel-Projekts findet Ihr am Ende von Teil 2 dieses Tutorials.

Schritt 1 - Vorbereitungen
In Expression Blend 4 wird ein neues Silverlight 4 Projekt erstellt. Der Oberfläche von MainPage.xaml wird ein Button hinzugefügt. Dieser Button dient später dazu, das ChildWindow aufzurufen.

Dann wird dem Silverlight-Projekt durch Rechtklick auf das Projekt -> Neues Element hinzufügen ... -> ChildWindow ein ChildWindow hinzugefügt. Dieses ChildWindow erhält den Namen "RingChildWindow.xaml". Ein Klick auf Ok fügt dem Projekt das neue ChildWindow hinzu. Das ChildWindow erhält eine Größe von 400px x 400px.

Schritt 2 - Styling der Vorlage
In Expression Blend 4 wird jetzt das RingChildWindow zur Bearbeitung angezeigt. Im Objektbaum der Registerkarte "Objekte und Zeitachsen" wird mit einem Linksklick das ChildWindow selektiert.



Mit einem Rechtklick auf das ChildWindow-Element im Objektbaum -> Vorlage bearbeiten -> Kopie bearbeiten ...



gelangt man in das Dialogfenster "Resource "Style" erstellen. Der neue Style wird "RingChildWindowStyle" genannt. Der Style wird definiert in der Anwendung, also in der Datei App.xaml.


Ein Klick auf Ok und man gelangt sofort in der Vorlage des ChildWindow. Wir werfen einen Blick in den Objektbaum der Vorlage in der Registerkarte "Objekte und Zeitachsen". Dort werden die folgenden Elemente selektiert und gelöscht:



Dann wird das Element ContentRoot selektiert. In der Registerkarte "Objekte" -> Formen wird "Ring" selektiert und dem ContentRoot-Element mit einem Doppelklick auf "Ring" hinzugefügt.



Per Drag&Drop wird das neue Arc-Element direkt unter das ContentRoot platziert.



Die Fill-Eigenschaft des Arc-Elements wird an die Background-Eigenschaft der Vorlage gebunden:




Damit kann der Brush für den Fill später einfach über den Background des ChildWindow festgelegt werden.

Die Eigenschaften HorizontalAlignment und VerticalAlignment des Arc-Elements werden jeweils auf Stretch gesetzt. Die Eigenschaften Width und Height werden beide auf "Automatisch" gesetzt. Der Eigenschaft "ArcThickness" wird auf den Wert 80 gesetzt.




Im Moment ist der Ring noch nicht sichtbar. Um das zu ändern, wird die Background-Eigenschaft für das erste und für das zweite Border-Element der Vorlage zurückgesetzt.



Außerdem wird für das Border-Steuerelement, das den ContentPresenter enthält, die Vorlagenbindung der Background-Eigenschaft zurückgesetzt.



Wir wechseln kurz mit einem Klick auf das Pfeilsymbol im Objektbaum der Vorlage zurück in das ChildWindow.



Dort erzeugen wir einen ansehnlichen Background für das Ring-Element.



Für das weitere Vorgehen ist es sinnvoll, die beiden Button-Steuerelemente "Ok" und "Cancel" zu löschen. Die EventHandler für die beiden Buttons werden ebenfalls gelöscht. Dann wechseln wir wieder in die Vorlage.

Jetzt soll der Chrome gestaltet werden. Der Chrome definiert bei einem rechteckigen ChildWindow die Fensterleiste. Standardmäßig ist der Chrome rechteckig. Da wir ein ringförmiges ChildWindow gestalten, soll auch der Chrome ringförmig sein.

Der Chrome ist ein einfaches Border-Steuerelement. Es befindet sich in einem Grid-Steuerelement.



Für dieses Grid-Steuerelement sind zwei Zeilen definiert. Ein Klick auf "RowDefinitions" zeigt, dass der Wert für die erste Zeile auf "1" und "Auto" gesetzt ist.



Der Wert für die zweite Zeile ist auf "1" und "Star" gesetzt:



Der Chrome hat die Zuweisung zur ersten Zeile, Row 0. Das bewirkt, dass die Zeile 1 (Row 0) automatisch ihre Größe entsprechend der Größe des Chrome anpaßt.

Das Chrome ist wie gesagt ein einfaches Border-Steuerelement. Deswegen können wir dem Chrome ein anderes Steuerelement hinzufügen, das visuell unsere Fensterleiste darstellen wird. Wir selektieren das Chrome und fügen mit einem Doppelklick ein Ring-Element hinzu.



Damit das soeben hinzugefügte Ring-Element ordentlich sichtbar wird, wird die Größe auf 80px x 80px gesetzt. Die Vorlage sieht jetzt so aus:



Die weiße Hintergrundfarbe kommt vom Chrome. Um das zu ändern, wird sowohl die Background-Eigenschaft als auch die BorderBrush-Eigenschaft des Chrome zurückgesetzt.

Dann wird die HorizontalAlignment-Eigenschaft des Arc-Elements auf "Rechts" gesetzt. Als Background-Eigenschaft für das Arc-Element verwenden wir den Brush, den auch wir für den Hauptring verwendet haben. Jetzt sieht unsere Vorlage so aus:



Schon ziemlich gut.

Jetzt wollen wir, dass der Chrome einen anderen VisualState bekommt, wenn der Mauszeiger darüberbewegt wird. Dazu müssen wir ein paar VisualState für das Arc-Element erzeugen. Damit keine Konflikte zu den Zuständen des ChildWindow entstehen, verwenden wir einen kleinen Trick. Wir erzeugen aus dem Arc-Element, das im Chrome ist, ein UserControl. Dazu wird das Arc-Element selektiert. Dann erzeugen wir mit einem Rechtklick -> Benutzersteuerelement erstellen ... ein UserControl.



Dieses UserControl erhält den Namen "ChromeHeaderRingUserControl".



Ein Klick auf "ok" und das neue UserControl kann bearbeitet werden. In ChromeHeaderRingUserControl.xaml wechseln wir zur Registerkarte "Zustände". Wir selektieren das Arc-Element und kopieren es mit Strg+C, Strg+V. Das neue Arc-Element erhält den Namen "MouseOverVisual". Der Z-Index wird auf "1" gesetzt. Den Brush der Fill-Eigenschaft wird so verändert, dass er insgesamt etwas heller leuchtet.



Der Wert für die Opacity wird auf "0" gesetzt.

Jetzt werden insgesamt 2 VisualState hinzugefügt. Diese werden "normal" und "mouseOver" genannt. Die Übergangsdauer wird auf "0,4" gesetzt. Wir selektieren den VisualState "mouseOver" und setzen den Wert der Opacity auf "100".





Jetzt muss das Projekt neu erstellt werden, damit die Änderungen am UserControl in der Vorlage des ChildWindow sichtbar sind.

Damit der Chrome, bzw. unser UserControl, einen anderen VisualState einnimmt, wenn man den Mauszeiger darüberbewegt, müssen wir kurz zu VisualStudio 2010 wechseln. Dort fügen wir in die CodeBehind-Datei des UserControl zwei EventHandler hinzu. Einen für MouseEnter und einen weiteren für MouseLeave.

Partial Public Class ChromeHeaderRingUserControl
    Inherits UserControl

    Public Sub New()
        ' Für das Initialisieren der Variablen erforderlich
        InitializeComponent()
    End Sub

  Private Sub ChromeHeaderRingUserControl_MouseEnter(ByVal sender As Object,
        ByVal e As System.Windows.Input.MouseEventArgs) Handles Me.MouseEnter

    VisualStateManager.GoToState(Me, "mouseOver", True)

  End Sub

  Private Sub ChromeHeaderRingUserControl_MouseLeave(ByVal sender As Object,
        ByVal e As System.Windows.Input.MouseEventArgs) Handles Me.MouseLeave

    VisualStateManager.GoToState(Me, "normal", True)

  End Sub

End Class



Unsere Vorlage für das ChildWindow ist jetzt soweit hergerichtet, dass das ChildWindow durch Darg&Drop auf den Chrome bewegt werden kann. Der Aufruf des ChildWindow erfolgt über den Button in MainPage.xaml. Wie das geht, brauche ich nicht zu beschreiben. Bevor wir das ChildWindow das erste mal aufrufen, wird der Wert für den BorderBrush des ChildWindow (nicht der Wert in der Vorlage) zurückgesetzt. Andernfalls wäre das visuelle Bild gestört.

F5 drücken und dann den Button klicken und das ChildWindow erscheint. Es kann durch Drag&Drop auf den Chrome bewegt werden. Aber hey, es ist kein Button für das Schließen vorhanden ...

Um einen Button für das Schließen hinzuzufügen, gehen wir erneut zurück in die Vorlage unseres ChildWindow. Im Objektbaum der Vorlage selektieren wir das Grid-Element.



Dann fügen wir mit einem Doppelklick dem selektierten Grid einen Button hinzu. Der Wert für das HorizontalAlignment wird auf "Rechts" gesetzt. Der Wert für das VerticalAlignment wird auf "Top" gesetzt. Der Button muss jetzt natürlich einen Style erhalten, der ebenfalls rund ist. Wie man das macht, beschreibe ich hier nicht. Ich nehme als Resource für einen runden Button-Style einen Style, den ich vorher entworfen habe. Das ist der RoundButtonStyle. Den Quellcode findet Ihr als Resource im Download. Die Farben passen zwar nicht zum Beispiel, aber er ist halt rund.

Der RoundButtonStyle wird dem Button hinzugefügt. Als Wert für die Content-Eigenschaft des Button wird ein kleines "x" eingegeben. Die Foreground-Eigenschaft erhält den selben Farbwert, wie der Background des Button. Der RoundButtonStyle ist so gestaltet, dass erst beim MouseOver VisualState die Farbe des kleinen "x" zu "Weiß" wechselt.

Etwas vergrößert sieht unsere ChildWindow-Vorlage jetzt so aus:



Damit die Vorlage des ChildWindow den hinzugefügten Button als Teil der Vorlage erkennt, muss der Button als Teil der Vorlage erstellt werden. Dafür wird der Button selektiert, Rechtklick -> Teil von ChildWindow erstellen -> CloseButton selektieren:



F5 Drücken, und die Gestaltung des ChildWindow mit einer Ringform ist fertiggestellt.

In Teil 2 beschreibe ich, wie man diesen Style um eine ringförmige Anordnung des Content ergänzt.

Download: Beispiel-Projekt mit vollständigem Quellcode. (Dies ist ein weiteres Beispiel, das in der Expression Gallery veröffentlicht ist.)

Viel Spass!

1 Kommentar: