Search code examples
c#wpfxamlwindow

How do i get a Menu in the Window bar?


I would like to know how to get a menu in the window bar, the same as Visual studio does.

Visual Studios Window

It would be good to be able to have File, Edit, etc on the left and the standard Minimize, Maximize and Close buttons on the right. Is this at all possible?

I have tried setting Window WindowStyle="None" and adding my own icons in the bar but it doesnt seem right but is this the only way?

This is what i have at the moment.

My Current Window

<Window
        Title="MainWindow" 
        Height="{x:Static SystemParameters.PrimaryScreenHeight}"
        Width="{x:Static SystemParameters.PrimaryScreenWidth}"
        Closing="Window_Closing"
        WindowState="Maximized">

Solution

  • You must create your custom window chrome using the WindowChrome class:

    The Window element in WPF is actually hosted in a non-WPF (non-client) host. This host includes the title bar (caption) and the standard buttons, an icon and the actual frame. This is known as window chrome.

    enter image description here

    Usually you can only modify the client area of a Window. But whith the help of the WindowChrome class, WPF allows the client area to extend into the non-client area.
    The disadvantage is that you would have to basically replicate the original non-client area in order to preserve the original look and feel. But after all you still get some basic behavior like maximizing the window on double click ou of the box.

    The following example is very basic, but should give you an idea how to achieve your task:

    enter image description here

    I highly recommend to follow the provided link to the WindowChrome class and read the remarks section, which contains very valuable information.
    You can use the actual system values provided by the static SystemParameters class to get the current dimension values e.g. SystemParameters.WindowResizeBorderThickness which you should use in your custom chrome style.

    Also note that to allow WPF to capture mouse events on you custom chrome's input elements like buttons or menus you must set the attached property WindowChrome.IsHitTestVisibleInChrome on each relevant element to true:

    WindowChrome.IsHitTestVisibleInChrome="True"
    

    The very basic style that creates the above visual is as followed:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:shell="clr-namespace:System.Windows.Shell;assembly=PresentationFramework">
    
    
      <Style x:Key="WindowStyle" TargetType="{x:Type Window}">
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="WindowChrome.WindowChrome">
          <Setter.Value>
            <WindowChrome NonClientFrameEdges="Right"
                          ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
          </Setter.Value>
        </Setter>
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="{x:Type Window}">
              <Border Background="{TemplateBinding Background}"
                      BorderBrush="{TemplateBinding BorderBrush}"
                      BorderThickness="{TemplateBinding BorderThickness}">
                <Grid Background="Transparent">
    
                  <AdornerDecorator>
                    <Border Background="Transparent" Margin="{x:Static SystemParameters.WindowNonClientFrameThickness}">
                      <ContentPresenter />
                    </Border>
                  </AdornerDecorator>
                  <ResizeGrip x:Name="WindowResizeGrip"
                              HorizontalAlignment="Right"
                              VerticalAlignment="Bottom"
                              Visibility="Collapsed"
                              IsTabStop="false" />
                  <Grid Height="{Binding Source={x:Static SystemParameters.WindowNonClientFrameThickness}, Path=Top}"
                        Background="#FF3F3F3F"
                        VerticalAlignment="Top">
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition />
                      <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
    
                    <!-- Custom window chrome -->
                    <StackPanel Grid.Column="0" Orientation="Horizontal"
                                Margin="{x:Static SystemParameters.WindowResizeBorderThickness}">
                      <Image Source="{TemplateBinding Icon}" />
                      <TextBlock Text="{TemplateBinding Title}"
                                 TextTrimming="CharacterEllipsis"
                                 VerticalAlignment="Center"
                                 Margin="16,0" />
                      <Menu shell:WindowChrome.IsHitTestVisibleInChrome="True">
                        <MenuItem Header="CustomChromeMenu">
                          <MenuItem Header="Action" />
                        </MenuItem>
                      </Menu>
                    </StackPanel>
    
                    <StackPanel Grid.Column="1"
                                Orientation="Horizontal"
                                HorizontalAlignment="Right">
                      <Button Width="45"
                              Height="{Binding Source={x:Static SystemParameters.WindowNonClientFrameThickness}, Path=Top}"
                              ToolTip="Minimize window"
                              ToolTipService.ShowDuration="5000"
                              shell:WindowChrome.IsHitTestVisibleInChrome="True">
                        <TextBlock Foreground="{Binding RelativeSource={RelativeSource AncestorType=Control}, Path=Foreground}"
                   FontFamily="Segoe MDL2 Assets"
                   FontSize="11"
                   Text="&#xE921;" />
                      </Button>
                      <Button ToolTip="Maximize window"
                              Width="45"
                              Height="{Binding Source={x:Static SystemParameters.WindowNonClientFrameThickness}, Path=Top}"
                              ToolTipService.ShowDuration="5000"
                              shell:WindowChrome.IsHitTestVisibleInChrome="True">
                        <TextBlock Foreground="{Binding RelativeSource={RelativeSource AncestorType=Control}, Path=Foreground}"
                   FontFamily="Segoe MDL2 Assets"
                   FontSize="11"
                   Text="&#xE922;" />
                      </Button>
                      <Button ToolTip="Close application"
                              ToolTipService.ShowDuration="5000"
                              Width="50"
                              Height="{Binding Source={x:Static SystemParameters.WindowNonClientFrameThickness}, Path=Top}"
                              shell:WindowChrome.IsHitTestVisibleInChrome="True">
                        <TextBlock Foreground="{Binding RelativeSource={RelativeSource AncestorType=Control}, Path=Foreground}"
                   FontFamily="Segoe MDL2 Assets"
                   FontSize="11"
                   Text="&#xE8BB;" />
                      </Button>
                    </StackPanel>
                  </Grid>
                </Grid>
              </Border>
              <ControlTemplate.Triggers>
                <Trigger Property="ResizeMode"
                         Value="CanResizeWithGrip">
                  <Setter TargetName="WindowResizeGrip"
                          Property="Visibility"
                          Value="Visible" />
                </Trigger>
              </ControlTemplate.Triggers>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
    </ResourceDictionary>