Metro Style Window in WPF

Follow the previous post, Metro Style ListBox in WPF, I am going to introduce the Metro Style Window in WPF.

MetroWindowResult

To do this, we have to create our own style on the Window Control.

First, create your new project, and then focus and right click on the window control.

CreateNewMetroWindowStyle

And then give it a name, here I have put MetroWindowStyle.

createMetroWindow

After the style is created, the very first thing is to see the structure of the style.

We see the style is divided into three part.

  • Setter for usual property
  • Setter for Template with Control Template inside
  • Style Trigger

So what we will do is to stop the default style of the window. We will also create our own title bar with buttons and title. Finally bind the buttons to specific event handlers for minimize, restore and exit functions.

Stop Default Window Style

To stop inheriting the default window style for a window, it is as easy as setting one property.

Simply put this line in the under the Background Setter in the Style.

<Setter Property="WindowStyle" Value="None" />

Create our own Title Bar and Buttons

To create the title bar, we will use Border, however, in order to ensure the content presenter will be filling the whole window, we will use DockPanel. So we will use a DockPanel to wrap the our Title Bar and the Content Presenter.

Inside our Title Bar, we will have another DockPanel which wraps the Title and three buttons namely minimize, restore and close.

So the code for the Control Panel is

<ControlTemplate TargetType="{x:Type Window}">
    <Grid>
        <Border x:Name="MainBorder"
            BorderThickness="0" Background="White" >
            <DockPanel LastChildFill="True">
                <Border x:Name="PART_TITLEBAR"
                    Margin="0,0,0,0"
                    Height="40"
                    DockPanel.Dock="Top"
                    Background="Transparent" MouseLeftButtonDown="PART_TITLEBAR_MouseLeftButtonDown">
                    <DockPanel LastChildFill="False">
                        <TextBlock Margin="4,0,0,4"
                                VerticalAlignment="Center"
                                Foreground="#FFAAAAAA"
                                TextWrapping="NoWrap"
                                Text="{TemplateBinding Title}"
                                FontSize="16" />
                        <Button x:Name="PART_CLOSE"
                            DockPanel.Dock="Right"
                            VerticalAlignment="Center" Margin="5"
                            Height="20" Width="20" Style="{DynamicResource MetroWindowButtonStyle}"
                                Click="PART_CLOSE_Click">
                            <Path Data="F1M54.0573,47.8776L38.1771,31.9974 54.0547,16.1198C55.7604,14.4141 55.7604,11.6511 54.0573,9.94531 52.3516,8.23962 49.5859,8.23962 47.8802,9.94531L32.0026,25.8229 16.1224,9.94531C14.4167,8.23962 11.6511,8.23962 9.94794,9.94531 8.24219,11.6511 8.24219,14.4141 9.94794,16.1198L25.8255,32 9.94794,47.8776C8.24219,49.5834 8.24219,52.3477 9.94794,54.0534 11.6511,55.7572 14.4167,55.7585 16.1224,54.0534L32.0026,38.1745 47.8802,54.0534C49.5859,55.7585 52.3516,55.7572 54.0573,54.0534 55.7604,52.3477 55.763,49.5834 54.0573,47.8776z"
                                    Stretch="Uniform" Fill="#FFAAAAAA" Width="10" Margin="0,0,0,0" ></Path>
                        </Button>
                        <Button x:Name="PART_MAXIMIZE_RESTORE"
                            DockPanel.Dock="Right" Margin="5"
                            HorizontalAlignment="Center"
                            VerticalAlignment="Center"
                                Height="20" Width="20" Style="{DynamicResource MetroWindowButtonStyle}"
                                Click="PART_MAXIMIZE_RESTORE_Click">
                            <Path Data="M4.3685131,23.127279L4.3685131,47.283243 47.117023,47.283243 47.117023,23.127279z M0,10.684L53.755001,10.684 53.755001,51.668001 0,51.668001z M8.5679998,0L58.668022,0 64,0 64,5.6864691 64,45.317999 58.668022,45.317999 58.668022,5.6864691 8.5679998,5.6864691z"
                                    Stretch="Uniform" Fill="#FFAAAAAA" Width="10" Margin="0,0,0,0" ></Path>
                        </Button>
                        <Button x:Name="PART_MINIMIZE"
                            HorizontalAlignment="Center"
                            VerticalAlignment="Center" Margin="5"
                            DockPanel.Dock="Right"
                                Height="20" Width="20" Style="{DynamicResource MetroWindowButtonStyle}"
                                Click="PART_MINIMIZE_Click" VerticalContentAlignment="Bottom">
                            <Button.Content>
                                <Path Data="M0,20L53.333,20 53.333,8.888 0,8.888z"
                                        Stretch="Uniform" Fill="#FFAAAAAA" Width="10" Margin="0,0,0,5"></Path>
                            </Button.Content>
                        </Button>
                    </DockPanel>
                </Border>

                <AdornerDecorator DockPanel.Dock="Bottom">
                    <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}"/>
                </AdornerDecorator>
            </DockPanel>
        </Border>
    </Grid>
</ControlTemplate>

Now you may find the Button is not up to Metro Standard, so from the code you may find I have created a new Style for it.

For the Style, I simply remove the border and set the background to gray. You can of course create your own style.

<Style x:Key="MetroWindowButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="FocusVisualStyle">
        <Setter.Value>
            <Style>
                <Setter Property="Control.Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Rectangle Margin="2" SnapsToDevicePixels="True" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
    <Setter Property="Background" Value="{x:Null}"/>
    <Setter Property="BorderBrush" Value="#FF707070"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Padding" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                    <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsDefaulted" Value="True">
                        <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" TargetName="border" Value="#FFBEE6FD"/>
                        <Setter Property="BorderBrush" TargetName="border" Value="#FF3C7FB1"/>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Background" TargetName="border" Value="#FFC4E5F6"/>
                        <Setter Property="BorderBrush" TargetName="border" Value="#FF2C628B"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Background" TargetName="border" Value="#FFF4F4F4"/>
                        <Setter Property="BorderBrush" TargetName="border" Value="#FFADB2B5"/>
                        <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="#FF838383"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Event Handler for Buttons

Till now we have finished the part on the style, let’s move onto the event handlers.

We will have three event handlers for buttons, they are functioning to minimizing, restoring and closing the window.

Closing

private void PART_CLOSE_Click(object sender, RoutedEventArgs e)
{
this.Close();
}

Minimizing

private void PART_MINIMIZE_Click(object sender, RoutedEventArgs e)
{
this.WindowState = System.Windows.WindowState.Minimized;
}

Restoring

private void PART_MAXIMIZE_RESTORE_Click(object sender, RoutedEventArgs e)
{
if (this.WindowState == System.Windows.WindowState.Normal)
{
this.WindowState = System.Windows.WindowState.Maximized;
}
else
{
this.WindowState = System.Windows.WindowState.Normal;
}
}

Finally, you may find one behavior is missing, that is the dragging of the window. If you try to drag it through button down on the title bar, you will find it is not functioning as expected.

So we also have to  implement this. But this is super easy. Just add an event handler for the border.

XAML
MouseLeftButtonDown="PART_TITLEBAR_MouseLeftButtonDown"
Code Behind

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

Summary

We are now capable to create our own style for Window Control. You can download the sample project here.

zipIconMetroWindows.zip

Advertisements

11 thoughts on “Metro Style Window in WPF

  1. Brother this is just superb, many many thanks, but i want to add an image on the background, how can i do this

    Reply
  2. Pingback: Metro Style Window in WPF | D Says

  3. Thank you for the tutorial!
    It helped me a lot, but I made some changes, I switched the Click event for a
    ICommand, so that the style is more reusable, and also added triggers to the buttons,
    so that they don’t appear if they cannot be clicked, for example, if the window as
    ResizeMode=”CanMinimize” then the maximize button doesn’t appear.

    Reply
  4. Thanks Steve!
    I was looking for something less than Modern UI or MahApps that would give my window that modern feel. This was just what I wanted.
    To give it that truly flat modern look, I also set
    WindowStyle=”None”
    AllowsTransparency=”True”

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s