Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create custom window chrome in wpf?

Tags:

window

wpf

xaml

How can I create a basic custom window chrome for a WPF window, that doesn't include the close button and still a moveable and resizeable window?

like image 264
Carl Weis Avatar asked Jul 22 '11 15:07

Carl Weis


3 Answers

You set your Window's WindowStyle="None", then build your own window interface. You need to build in your own Min/Max/Close/Drag event handlers, but Resizing is still maintained.

For example:

<Window 
    WindowState="Maximized"
    WindowStyle="None"
    WindowStartupLocation="CenterScreen"
    MaxWidth="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Width}"
    MaxHeight="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Height}"
>

    <DockPanel x:Name="RootWindow">
        <DockPanel x:Name="TitleBar" DockPanel.Dock="Top">
            <Button x:Name="CloseButton" Content="X"
                    Click="CloseButton_Click"
                    DockPanel.Dock="Right" />
            <Button x:Name="MaxButton" Content="Restore"
                    Click="MaximizeButton_Click"
                    DockPanel.Dock="Right" />
            <Button x:Name="MinButton" Content="Min"
                    Click="MinimizeButton_Click"
                    DockPanel.Dock="Right" />

            <TextBlock HorizontalAlignment="Center">Application Name</TextBlock>
        </DockPanel>

        <ContentControl Content="{Binding CurrentPage}" />
    </DockPanel>

</Window>

And here's some example code-behind for common window functionality

/// <summary>
/// TitleBar_MouseDown - Drag if single-click, resize if double-click
/// </summary>
private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e)
{
    if(e.ChangedButton == MouseButton.Left)
        if (e.ClickCount == 2)
        {
            AdjustWindowSize();
        }
        else
        {
            Application.Current.MainWindow.DragMove();
        }
 }

/// <summary>
/// CloseButton_Clicked
/// </summary>
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
   Application.Current.Shutdown();
}

/// <summary>
/// MaximizedButton_Clicked
/// </summary>
private void MaximizeButton_Click(object sender, RoutedEventArgs e)
{
    AdjustWindowSize();
}

/// <summary>
/// Minimized Button_Clicked
/// </summary>
private void MinimizeButton_Click(object sender, RoutedEventArgs e)
{
    this.WindowState = WindowState.Minimized;
}

/// <summary>
/// Adjusts the WindowSize to correct parameters when Maximize button is clicked
/// </summary>
private void AdjustWindowSize()
{
    if (this.WindowState == WindowState.Maximized)
    {
        this.WindowState = WindowState.Normal;
        MaxButton.Content = "1";
    }
    else
    {
        this.WindowState = WindowState.Maximized;
        MaxButton.Content = "2";
    }

}
like image 108
Rachel Avatar answered Oct 13 '22 17:10

Rachel


.NET 4.5 added a new class that greatly simplifies this.

The WindowChrome class enables you to extend Windows Presentation Foundation (WPF) content into the non-client area of a window that is typically reserved for the operating system’s window manager.

You can find a tutorial here.

And here's a short example usage.

like image 55
dss539 Avatar answered Oct 13 '22 16:10

dss539


I've just used the example below for .net 4.5 and it works very well. Interestingly, it uses a code behind for a resource dictionary for the click events. All you have to do is reference the resource dictionary in your app.xaml file and then assign the Window the Style CustomWindowStyle. This was shamelessly stolen from http://www.eidias.com/blog/2014/1/27/restyle-your-window.

<ResourceDictionary x:Class="WpfApp7.WindowStyle"
                    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">


    <Style x:Key="CustomWindowStyle" TargetType="{x:Type Window}">
        <Setter Property="WindowChrome.WindowChrome">
            <Setter.Value>
                <WindowChrome CaptionHeight="30"
                              CornerRadius="4"
                              GlassFrameThickness="0"
                              NonClientFrameEdges="None"
                              ResizeBorderThickness="5"
                              UseAeroCaptionButtons="False" />
            </Setter.Value>
        </Setter>

        <Setter Property="BorderBrush" Value="Black" />
        <Setter Property="Background" Value="Gray" />

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Grid>
                        <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="5,30,5,5">
                            <AdornerDecorator>
                                <ContentPresenter />
                            </AdornerDecorator>
                        </Border>

                        <Grid Height="30"
                            VerticalAlignment="Top">

                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>

                            <StackPanel Orientation="Horizontal" Margin="5,0">
                                <Button Content="A" Margin="0,0,5,0" VerticalAlignment="Center" Click="Button_Click" WindowChrome.IsHitTestVisibleInChrome="True"/>
                                <Button Content="B" Margin="0,0,5,0" VerticalAlignment="Center" Click="Button_Click" WindowChrome.IsHitTestVisibleInChrome="True"/>
                                <Button Content="C" Margin="0,0,5,0" VerticalAlignment="Center" Click="Button_Click" WindowChrome.IsHitTestVisibleInChrome="True"/>
                                <Button Content="D" Margin="0,0,5,0" VerticalAlignment="Center" Click="Button_Click" WindowChrome.IsHitTestVisibleInChrome="True"/>
                            </StackPanel>


                            <TextBlock Margin="5,0,0,0"
                                       VerticalAlignment="Center"
                                       HorizontalAlignment="Center"
                                       FontSize="16"
                                       Foreground="White"
                                       Text="{TemplateBinding Title}" 
                                       Grid.Column="1"/>


                            <StackPanel Orientation="Horizontal"
                                        Grid.Column="2">
                                <Button x:Name="btnClose"
                                    Width="15"
                                    Margin="5"
                                    Click="CloseClick"
                                    Content="X"
                                    WindowChrome.IsHitTestVisibleInChrome="True" />


                                <Button x:Name="btnRestore"
                                    Width="15"
                                    Margin="5"
                                    Click="MaximizeRestoreClick"
                                    Content="#"
                                    WindowChrome.IsHitTestVisibleInChrome="True" />

                                <Button x:Name="btnMinimize"
                                    Width="15"
                                    Margin="5"
                                    VerticalContentAlignment="Bottom"
                                    Click="MinimizeClick"
                                    Content="_"
                                    WindowChrome.IsHitTestVisibleInChrome="True" />
                            </StackPanel>
                        </Grid>

                    </Grid>

                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

And for the code behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp7
{
    public partial class WindowStyle : ResourceDictionary
    {
        public WindowStyle()
        {
            InitializeComponent();
        }

        private void CloseClick(object sender, RoutedEventArgs e)
        {
            var window = (Window)((FrameworkElement)sender).TemplatedParent;
            window.Close();
        }

        private void MaximizeRestoreClick(object sender, RoutedEventArgs e)
        {
            var window = (Window)((FrameworkElement)sender).TemplatedParent;
            if (window.WindowState == System.Windows.WindowState.Normal)
            {
                window.WindowState = System.Windows.WindowState.Maximized;
            }
            else
            {
                window.WindowState = System.Windows.WindowState.Normal;
            }
        }

        private void MinimizeClick(object sender, RoutedEventArgs e)
        {
            var window = (Window)((FrameworkElement)sender).TemplatedParent;
            window.WindowState = System.Windows.WindowState.Minimized;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Hello!");
        }
    }
}
like image 12
Simon Stanford Avatar answered Oct 13 '22 18:10

Simon Stanford