Home > Softwareentwicklung > Rahmenlose Fenster mit WPF

Rahmenlose Fenster mit WPF

April 20th, 2009 Bernd

NonRectWindow

Achtung, das folgende Beispiel bringt wahrscheinlich keinen Nutzen für den täglichen Umgang mit WPF!

EGAL! Manchmal muss man eben auch spielen :-) . Rahmenlose Fenster sind einfach cool. Wenn dann auch noch ein guter Designer mit im Spiel ist, sieht das Ganze auch besser aus als bei meinem Versuch.

Ok, Design beiseite. Was ist zu tun um eine Anwendung mit einem rahmenlosen Fenster zu erstellen?

Der erste Schritt besteht darin, an dem Fenster der Applikation drei Eigenschaften entsprechend zu setzen:

  • AllowsTransparency auf true
  • WindowStyle auf None – in Verbindung mit AllowsTransparency=”True” wird erreicht, dass der Fensterrahmen und die Titelzeile verschwinden
  • Background auf Transparent
    <Window x:Class="NonRectShapedWindowWPF.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Width="215"
        Height="215"
        AllowsTransparency="True"
        WindowStyle="None"
        Background="Transparent">
    ...

    In meinem Beispiel habe ich mich dazu entschieden das UI aus zwei Kreisen zusammenzusetzen. Der grosse Kreis dient als “Hauptrahmen” der Anwendung und der kleine Kreis enthält einen “Close” Button.

  • ...
    <Grid Height="200" Width="200">
        <Ellipse Fill="Red" Stroke="DarkRed"
                 MouseLeftButtonDown="OnCircleMouseLeftButtonDown">
            <Ellipse.BitmapEffect>
                <OuterGlowBitmapEffect GlowSize="8" GlowColor="OrangeRed" />
            </Ellipse.BitmapEffect>
        </Ellipse>
    
        <Canvas...>
    
        <Button Margin="150 -150 0 0"
                Template="{StaticResource closeButton}"
                FontFamily="Webdings"
                FontWeight="Bold"
                FontSize="10"
                Content="r"
                Click="OnCloseButtonClick"
                ToolTip="Close">
        </Button>
    </Grid>
    ...

Der eigentliche Inhalt der Anwendung versteckt sich in dem zusammengeklappten <Canvas> Element. Die Details dazu gibt es weiter unten.

Wie in dem XAML Code zu sehen ist, wird der “Close” Button über die Margin Eigenschaft an der gewünschten Stelle positioniert. Um dem Button ein rundes Aussehen zu verpassen, habe ich ein ControlTemplate erstellt.

...
<ControlTemplate x:Key="closeButton" TargetType="{x:Type Button}">
    <Grid>
        <Ellipse Fill="Red" Stroke="DarkRed"
                 Width="25" Height="25"/>

        <Label Content="{TemplateBinding Content}"
               Foreground="Black"
               HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</ControlTemplate>
...

Um dem Anwender ein Verschieben des Fensters zu ermöglichen, fügt man einen Eventhandler für das MouseLeftButtonDown Event hinzu. Und zwar an dem Element, mit dem das Fenster verschoben werden soll. Das könnte z.B. eine eigene Titelleiste sein, oder wie bei mir irgendein anderes, sichtbares Element. Der Code in dem Eventhandler ist sehr einfach:

private void OnCircleMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    DragMove();
}

Ein weiterer Eventhandler wird für das Click Event unseres “Close” Buttons benötigt um das Fenster zu schliessen:

private void OnCloseButtonClick(object sender, RoutedEventArgs e)
{
    Close();
}

Damit sind die wichtigsten Schritte gemacht, um ein rahmenloses Fenster mit WPF zu erstellen. Es kann vom Anwender verschoben und geschlossen werden. Um ein bisschen Action in das Beispiel zu bringen, gibt es noch eine kleine Animation, die Text durch das Fenster scrollen lässt. Der Code dazu sieht so aus:

...
<Canvas Height="100" Width="120" ClipToBounds="True">
    <TextBlock x:Name="_text"
               Height="100" Width="120"
               VerticalAlignment="Center" HorizontalAlignment="Center"
               TextWrapping="Wrap"
               FontFamily="Tahoma" FontSize="12">
            <TextBlock.Text>
                Diese Anwendung ist völlig sinnlos. Zu nichts zu gebrauchen. Und doch hat es viel Spass
                gemacht sie zu erstellen.
            </TextBlock.Text>
            <TextBlock.Triggers>
                <EventTrigger RoutedEvent="TextBlock.Loaded" >
                  <BeginStoryboard>
                    <Storyboard>
                      <DoubleAnimation
                        Storyboard.TargetName="_text"
                        Storyboard.TargetProperty="(Canvas.Top)"
                        Duration="0:0:4"
                        From="110" To="-80"
                        RepeatBehavior="Forever"/>
                    </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </TextBlock.Triggers>
    </TextBlock>
</Canvas>
...

Das komplette Beispiel kann hier heruntergeladen werden:

Kick it on dotnet-kicks.de
  1. April 27th, 2009 at 08:14 | #1

    Echt cool!
    Und sinnlos ist das ganz und gar nicht:
    1. Hat man viel dazu gelernt, wie man so etwas umsetzt (wäre mir auf Anhieb nicht eingefallen).
    2. Man kann auch Anwendungen bauen, bei denen unten ein kleines Eck fehlt, als kleinen optischen Pepp. Oder vielleicht Features nutzen wie in Office 2007 (Symbole in der Titelleiste), oder wie die neuen Adobe CS4 Produkte (komplettes Skin inkl. Titelleiste).

  2. Martin
    April 27th, 2009 at 08:53 | #2

    Und ob das einen Nutzen hat!!
    Es hat soeben ein kleines Designproblem in unserer Anwendung behoben. Dort liegen Fenster übereinander, die aber nicht als eigenständige Fenster erkennbar sein sollen.

    Danke dafür!

  3. admin
    April 27th, 2009 at 12:17 | #3

    Danke für das Feedback! Wahrscheinlich werde ich es tatsächlich demnächst in einer realen Anwendung brauchen.

  4. admin
    April 27th, 2009 at 12:17 | #4

    Cool, freut mich, dass es Dir geholfen hat!

  5. November 29th, 2009 at 21:22 | #5

    hallo bernd,
    so sinnlos ist das gar nicht.
    ich kann dein Beispiel sehr gut gebrauchen
    danke für dein Beispiel
    gruß
    Raimund

  6. May 24th, 2010 at 11:13 | #6

    Danke für das Beispiel!

    Stellt sich noch die Frage, ob man den VS-Designer dazu bringen kann, auch den Fensterrahmen auszublenden – anstatt nur zur Laufzeit…

  1. No trackbacks yet.
Comments are closed.