Home > C#, Universal Windows Platform > Easily manage the Title Bar in Windows 10 apps

Easily manage the Title Bar in Windows 10 apps

19/05/2015

Windows 10 apps run in a window like any standard desktop application. This means that now they have a title bar, that by default is gray, has the name of the app on the left and the standard three button on the right. However, if we need, we can customize its appearance and colors.

To reach this goal, we can leverage the ApplicationView.GetForCurrentView().TitleBar property. So, we need to do this via code. For example:

var titleBar = ApplicationView.GetForCurrentView().TitleBar;
titleBar.BackgroundColor = Colors.DarkBlue;
titleBar.ForegroundColor = Colors.White;
titleBar.ButtonBackgroundColor = Colors.Maroon;
titleBar.ButtonForegroundColor = Colors.Yellow;

With these instructions, we obtain the following chrome:

Windows 10 app Title Bar with custom chrome

Windows 10 app Title Bar with custom chrome

This solution works great, but we can improve it by defining the appropriate attached properties on the Page class, so that we can customize Title Bar colors via XAML:

public static class TitleBar
{
    public static readonly DependencyProperty ForegroundColorProperty =
        DependencyProperty.RegisterAttached("ForegroundColor", typeof(Color),
        typeof(TitleBar), 
        new PropertyMetadata(null, OnForegroundColorPropertyChanged));

    public static Color GetForegroundColor(DependencyObject d)
    {
        return (Color)d.GetValue(ForegroundColorProperty);
    }

    public static void SetForegroundColor(DependencyObject d, Color value)
    {
        d.SetValue(ForegroundColorProperty, value);
    }

    private static void OnForegroundColorPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var color = (Color)e.NewValue;
        var titleBar = ApplicationView.GetForCurrentView().TitleBar;
        titleBar.ForegroundColor = color;
    }

    public static readonly DependencyProperty BackgroundColorProperty =
        DependencyProperty.RegisterAttached("BackgroundColor", typeof(Color),
        typeof(TitleBar), 
        new PropertyMetadata(null, OnBackgroundColorPropertyChanged));

    public static Color GetBackgroundColor(DependencyObject d)
    {
        return (Color)d.GetValue(BackgroundColorProperty);
    }

    public static void SetBackgroundColor(DependencyObject d, Color value)
    {
        d.SetValue(BackgroundColorProperty, value);
    }

    private static void OnBackgroundColorPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var color = (Color)e.NewValue;
        var titleBar = ApplicationView.GetForCurrentView().TitleBar;
        titleBar.BackgroundColor = color;
    }

    public static readonly DependencyProperty ButtonForegroundColorProperty =
        DependencyProperty.RegisterAttached("ButtonForegroundColor", typeof(Color),
        typeof(TitleBar), 
        new PropertyMetadata(null, OnButtonForegroundColorPropertyChanged));

    public static Color GetButtonForegroundColor(DependencyObject d)
    {
        return (Color)d.GetValue(ButtonForegroundColorProperty);
    }

    public static void SetButtonForegroundColor(DependencyObject d, Color value)
    {
        d.SetValue(ButtonForegroundColorProperty, value);
    }

    private static void OnButtonForegroundColorPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var color = (Color)e.NewValue;
        var titleBar = ApplicationView.GetForCurrentView().TitleBar;
        titleBar.ButtonForegroundColor = color;
    }

    public static readonly DependencyProperty ButtonBackgroundColorProperty =
        DependencyProperty.RegisterAttached("ButtonBackgroundColor", typeof(Color),
        typeof(TitleBar), 
        new PropertyMetadata(null, OnButtonBackgroundColorPropertyChanged));

    public static Color GetButtonBackgroundColor(DependencyObject d)
    {
        return (Color)d.GetValue(ButtonBackgroundColorProperty);
    }

    public static void SetButtonBackgroundColor(DependencyObject d, Color value)
    {            
        d.SetValue(ButtonBackgroundColorProperty, value);
    }

    private static void OnButtonBackgroundColorPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var color = (Color)e.NewValue;
        var titleBar = ApplicationView.GetForCurrentView().TitleBar;
        titleBar.ButtonBackgroundColor = color;
    }
}

These attached properties allow to set the same properties we have seen before, but now directly in XAML:

<Page
    x:Class="FirstDemo.MainPage"
    local:TitleBar.BackgroundColor="DarkBlue"
    local:TitleBar.ForegroundColor="White"
    local:TitleBar.ButtonBackgroundColor="Maroon"
    local:TitleBar.ButtonForegroundColor="Yellow"
    ...>

It’s more elegant and removes the need of code-behind. Note that other properties are available:

  • ButtonHoverBackgroundColor
  • ButtonHoverForegroundColor
  • ButtonInactiveBackgroundColor
  • ButtonInactiveForegroundColor
  • ButtonPressedBackgroundColor
  • ButtonPressedForegroundColor
  • InactiveBackgroundColor
  • InactiveForegroundColor

Using the same approach we have just analyzed, we can easily add the corresponding attached properties.

But we can do more. First of all, we can extend the UI into the Title Bar, making it a “chromeless” app. We need just one line of code:

CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;

Note that in this case we are using CoreApplication.GetCurrentView, while in the previous snippet we set colors with ApplicationView.GetForCurrentView. In particular, we change the value of the ExtendViewIntoTitleBar property.

However, if we remove the title bar at all, we can’t move the window around. Actually, there is an area immediately to the left of title bar buttons which can be grabbed to drag the window, but it’s quite small and users will not expect this behavior.

The correct solution is to use the Window.Current.SetTitleBar method to set an element to act like the default title bar. So, let’s try to add this feature with a Behavior. The first thing to do is to add a reference to the Behavior SDK:

Adding the Behavior SDK to the project

Adding the Behavior SDK to the project

For the moment, we can ignore the compatibility warning. Now define the TitleBarBehavior:

public class TitleBarBehavior : DependencyObject, IBehavior
{
    public DependencyObject AssociatedObject { get; private set; }

    public void Attach(DependencyObject associatedObject)
    {
        var newTitleBar = associatedObject as UIElement;
        if (newTitleBar == null)
            throw new ArgumentException(
                "TitleBarBehavior can be attached only to UIElement");

        Window.Current.SetTitleBar(newTitleBar);
    }

    public void Detach() { }

    public bool IsChromeless
    {
        get { return (bool)GetValue(IsChromelessProperty); }
        set { SetValue(IsChromelessProperty, value); }
    }

    public static readonly DependencyProperty IsChromelessProperty =
        DependencyProperty.Register("IsChromeless",
        typeof(bool),
        typeof(TitleBarBehavior),
        new PropertyMetadata(false, OnIsChromelessChanged));

    private static void OnIsChromelessChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        CoreApplication.GetCurrentView().TitleBar
            .ExtendViewIntoTitleBar = (bool)e.NewValue;
    }
}

In the Attach method (lines 5-13), we verify that the associated object is a UIElement and, if so, we invoke the Window.Current.SetTitleBar method to use it as Title Bar. Now let’s take a look to the following XAML:

<Page
    ...
    xmlns:i="using:Microsoft.Xaml.Interactivity"
    ...>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Border x:Name="customTitleBar" VerticalAlignment="Top" Height="32">
            <Border.Background>
                <LinearGradientBrush>
                    <GradientStop Color="Blue" Offset="0" />
                    <GradientStop Color="WhiteSmoke" Offset="1.0" />
                </LinearGradientBrush>
            </Border.Background>
            <StackPanel Margin="12,5,5,5" Orientation="Horizontal">
                <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="" 
                          Foreground="White" VerticalAlignment="Center" Margin="0,0,8,0" />
                <TextBlock Text="My awesome app title" Foreground="White"
                           VerticalAlignment="Center"/>
            </StackPanel>

            <i:Interaction.Behaviors>
                <local:TitleBarBehavior IsChromeless="True"/>
            </i:Interaction.Behaviors>
        </Border>
        <Grid Grid.Row="1">
            ...
        </Grid>
    </Grid>
</Page>

Note that the TitleBarBehavior is attached to the customTitleBar object (lines 25-28). Running the app, we’ll see the following output:

Our app with a custom title bar

Our app with a custom title bar

In this way, Windows will handle input to the title bar XAML, so that we can move the window by dragging the elements in the title bar, or invoke the title bar context menu by right-clicking.

  1. 15/08/2015 at 15:44

    That’s awesome, I wonder if there is how to completely hide the app bar. Can I instantiate a UIElement null and set it with Window.Current.SetTitleBar(null)?

    • 16/08/2015 at 12:09

      You just need to use this: CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;

  1. No trackbacks yet.
Comments are closed.
%d bloggers like this: