Customize Window header Style

10 בMarch 2016

אין תגובות

In case you demand some extras from your MainWindow as programs like Microsoft Office did,
Lets say extra icons, menus , buttons or whatever.
The built in Window of System.Window type and its API in Xaml is very uncomfortable for customization and guess what , you the one who need to do all the dirty work. All of it? well I gonna help you to how to start.

image

In this screen shot I have,
1 . Icon on left (standard)
2. App name at left (standard)
3.  details on center (extra)
4. app special menu at right (extra)
5. window buttons at left (kind of standard)
So, first you main window set it as WindowStyle = none and define a region in the upper part for your customize header.
The main window code:

<Window x:Class="customWindowStyle.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:customWindowStyle"

        mc:Ignorable="d"

        Title="" Height="350" Width="525" WindowStyle="None">

    <Window.DataContext>

        <local:shelViewModel/>

    </Window.DataContext>


    <Grid Margin="2">

        <Grid.RowDefinitions>

            <!--caption-->

            <RowDefinition Height="35" />

            <!--main content-->

            <RowDefinition Height="1*" />

        </Grid.RowDefinitions>


        <ContentControl Grid.Row="0" Margin="-5">

            <local:WindowCaption/>

        </ContentControl>


        <ContentControl Grid.Row="1">

        </ContentControl>

    </Grid>

</Window>


Now, define your header it is just a regular UserControl to planning in the main window upper part,
Here is my caption (header) xaml code, contains all the styles in one file,  include the my version for window buttons (close minimize etc.)

<UserControl x:Class="customWindowStyle.WindowCaption"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

             xmlns:local="clr-namespace:customWindowStyle"

             mc:Ignorable="d"

            >

    <UserControl.Resources>

        <ResourceDictionary>


            <Style x:Key="Top_MenuStyle" TargetType="{x:Type Menu}">

                <Setter Property="Cursor" Value="Hand"/>

                <Setter Property="ItemContainerStyle" Value="{DynamicResource Top_MenuItemStyle}"/>

                <Setter Property="Template">

                    <Setter.Value>

                        <ControlTemplate TargetType="{x:Type Menu}">

                            <Border BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true" Height="30" >

                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>

                            </Border>

                        </ControlTemplate>

                    </Setter.Value>

                </Setter>

            </Style>


            <Style TargetType="{x:Type Separator}" x:Key="TopMenuSeparatorStyle">

                <Setter Property="Template">

                    <Setter.Value>

                        <ControlTemplate TargetType="{x:Type Separator}">

                            <Grid Margin="0,6,0,4" SnapsToDevicePixels="true">

                                <Rectangle Fill="#E0E0E0" Height="1" Margin="1,0,1,1"/>

                                <Rectangle Fill="White" Height="1" Margin="1,1,1,0"/>

                            </Grid>

                        </ControlTemplate>

                    </Setter.Value>

                </Setter>

            </Style>


            <Style x:Key="window_function_btns" TargetType="{x:Type Button}">

                <Setter Property="VerticalAlignment" Value="Top" />

                <Setter Property="Template">

                    <Setter.Value>

                        <ControlTemplate TargetType="{x:Type Button}">

                            <Border x:Name="border" Width="22" Height="22" CornerRadius="1" Background="Transparent" BorderThickness="0" Margin="0,3,3,3">

                                <ContentPresenter HorizontalAlignment="Stretch"  RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Stretch" Margin="3"/>

                            </Border>

                            <ControlTemplate.Triggers>

                                <Trigger Property="IsMouseOver" Value="True">

                                    <Setter Property="Background" TargetName="border" Value="#c00000"/>

                                </Trigger>

                                <Trigger Property="IsKeyboardFocused" Value="true"/>

                                <Trigger Property="ToggleButton.IsChecked" Value="true"/>

                                <Trigger Property="IsEnabled" Value="false">

                                    <Setter Property="Foreground" Value="#ADADAD"/>

                                </Trigger>

                            </ControlTemplate.Triggers>

                        </ControlTemplate>

                    </Setter.Value>

                </Setter>

            </Style>


        </ResourceDictionary>

    </UserControl.Resources>


    <Grid Background="#404040">

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="auto"/>

            <ColumnDefinition Width="5*"/>

            <ColumnDefinition Width="1*"/>

            <ColumnDefinition Width="auto"/>


        </Grid.ColumnDefinitions>


        <Grid Grid.Column="0" >

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="Auto"/>

                <ColumnDefinition Width="Auto"/>

            </Grid.ColumnDefinitions>

            <TextBlock Text="My Program" Grid.Column="1"  FontFamily="Arial" FontSize="16" FontWeight="ExtraLight" Foreground="#16c48a" Margin="5" VerticalAlignment="Center"  ToolTip="{Binding TitleBar.VesrionBuildToolTip , FallbackValue={x:Null}}"/>

            <Image Grid.Column="0" Margin="2" Source="/ggle.bmp" Stretch="UniformToFill" Width="35" Height="35"></Image>

        </Grid>


        <TextBlock Text="Program name" Grid.Column="1" HorizontalAlignment="Center" FontFamily="Arial" FontSize="12" FontWeight="Bold" Foreground="White" VerticalAlignment="Center"/>


        <Menu Grid.Column="2" IsMainMenu="True" HorizontalContentAlignment="Stretch" HorizontalAlignment="Right" Style="{StaticResource Top_MenuStyle}" Margin="0,0,15,0">

            <MenuItem Header="My Menu" TextBlock.Foreground="Red">

                <MenuItem Header="asd"  Name="Main_StoneTab_OpenFromFile_Item"

                          InputGestureText="asd"

                          Command="{Binding OpenFromFileCommand, FallbackValue={x:Null}}" />


                <Separator Style="{StaticResource TopMenuSeparatorStyle}"/>

                <MenuItem Header="open"

                        Command="{Binding OpenInfoCommand,FallbackValue={x:Null}}"  Name="Main_StoneTab_Info_Item"

                            InputGestureText="ctrl +O"/>

                <MenuItem Header="Save" Name="ddd"

                            InputGestureText="Ctrl+S"

                          Command="{Binding ShowMessagesCommand , FallbackValue={x:Null}}"/>

            </MenuItem>


        </Menu>


        <StackPanel Grid.Column="4" Orientation="Horizontal" HorizontalAlignment="Right">

            <Button  Command="{x:Static SystemCommands.MinimizeWindowCommand}" Style="{DynamicResource window_function_btns}" Name="Main_MenuItems_Minimize_Button">

                <Grid>

                    <Rectangle Fill="#FFC4C7C9"  Height="2" Margin="3,0,3,3" VerticalAlignment="Bottom"/>

                </Grid>

            </Button>

            <Button Command="{x:Static SystemCommands.MaximizeWindowCommand}" Style="{DynamicResource window_function_btns}" Name="Main_MenuItems_maximize_Button">

                <Grid>

                    <Border BorderBrush="#FFC4C7C9" BorderThickness="2"  Height="13" Width="13" Margin="1" />

                </Grid>

            </Button>

            <Button  Command="{x:Static SystemCommands.CloseWindowCommand}" Style="{DynamicResource window_function_btns}">

                <Grid>

                    <Rectangle Fill="#FFC4C7C9" Height="Auto" Margin="3,7" VerticalAlignment="Stretch" RenderTransformOrigin="0.5,0.5" d:LayoutOverrides="VerticalAlignment" StrokeThickness="0">

                        <Rectangle.RenderTransform>

                            <TransformGroup>

                                <ScaleTransform/>

                                <SkewTransform/>

                                <RotateTransform Angle="-45"/>

                                <TranslateTransform/>

                            </TransformGroup>

                        </Rectangle.RenderTransform>

                    </Rectangle>

                    <Rectangle Fill="#FFC4C7C9" Stroke="Black" StrokeThickness="0" Height="Auto" Margin="3,7" VerticalAlignment="Stretch" RenderTransformOrigin="0.5,0.5" d:LayoutOverrides="VerticalAlignment">

                        <Rectangle.RenderTransform>

                            <TransformGroup>

                                <ScaleTransform/>

                                <SkewTransform/>

                                <RotateTransform Angle="45"/>

                                <TranslateTransform/>

                            </TransformGroup>

                        </Rectangle.RenderTransform>

                    </Rectangle>

                </Grid>

            </Button>

        </StackPanel>

    </Grid>

</UserControl>

Now about to the standard window buttons (close, minimize etc.) that we lost once we set the main window style as none, we can see in the Xaml above some version of drawing them , yet you need a functionality.. of course it is possibly to bind them to regular Icommand in your ViewModel and solve them as you wish, but I think it is an extra code so my idea to solve them as much as possible near to Application backbone.. here is my version

public partial class App : Application

    {


        private bool resoreMaximizeFlag;

        private Window _window;


        protected override void OnActivated(EventArgs e)

        {

            base.OnActivated(e);


            _window = this.MainWindow;


            _window.CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, OnSystemCommandCloseWindow));

            _window.CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, OnSystemCommandMinimizeWindow));

            _window.CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, OnSystemCommandMaximizeWindow));

        }


        private void OnSystemCommandCloseWindow(object sender, ExecutedRoutedEventArgs e)

        {

            SystemCommands.CloseWindow(_window);

        }


        private void OnSystemCommandMinimizeWindow(object sender, ExecutedRoutedEventArgs e)

        {

            SystemCommands.MinimizeWindow(_window);

        }


        private void OnSystemCommandMaximizeWindow(object sender, ExecutedRoutedEventArgs e)

        {

            if(! resoreMaximizeFlag)

            SystemCommands.MaximizeWindow(_window);

            else

                SystemCommands.RestoreWindow(_window);


           resoreMaximizeFlag =  !resoreMaximizeFlag;


        }

   }


הוסף תגובה
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *