How to Add an Extra Button to the Window's Title Bar

How to add an extra button to the window's title bar?

UPDATE: Added a solution that will work with Aero enabled for Windows Vista and Windows 7



***Non-Aero Solution***

The non-client area of a window interaction is managed by a series of non-client specfic messages. For example WM_NCPAINT message is sent to the window procedure to paint the non-client area.

I have never done this from .NET, but I suspect you can overide the WndProc and handle the WM_NC* messages to achieve what you want.

Update: Since I never tried this from .NET I got a few minutes and thought I would give it a quick try.

Trying this on Windows 7, I found that I needed to disable the Themes for the Window if I wanted to OS to do the base rendering of the non-client area. So here is a short test. I used GetWindowDC to get the DC of the entire window rather than GetDCEx, that was just because I could interop that from memory and did not have lookup all the flag constants for GetDcEx. And of course the code could do with more error checking.

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
public partial class CustomBorderForm : Form
{
const int WM_NCPAINT = 0x85;

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindowDC(IntPtr hwnd);

[DllImport("user32.dll", SetLastError = true)]
public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);

[DllImport("user32.dll", SetLastError = true)]
public static extern void DisableProcessWindowsGhosting();

[DllImport("UxTheme.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr SetWindowTheme(IntPtr hwnd, string pszSubAppName, string pszSubIdList);

public CustomBorderForm()
{
// This could be called from main.
DisableProcessWindowsGhosting();

InitializeComponent();
}

protected override void OnHandleCreated(EventArgs e)
{
SetWindowTheme(this.Handle, "", "");
base.OnHandleCreated(e);
}

protected override void WndProc(ref Message m)
{
base.WndProc(ref m);

switch (m.Msg)
{
case WM_NCPAINT:
{
IntPtr hdc = GetWindowDC(m.HWnd);
using (Graphics g = Graphics.FromHdc(hdc))
{
g.FillEllipse(Brushes.Red, new Rectangle((Width-20)/2, 8, 20, 20));
}
ReleaseDC(m.HWnd, hdc);
}
break;
}
}
}
}

Btw. I called DisableProcessWindowsGhosting, this will stop the OS from drawing the non-client area if the application takes too long to respond to windows messages. If you do not do this, then in some situations the border will be renderd but your adornments will not be shown. So that depends on your requirements it that is right for you or not.



***Aero supported solution***

Prompted by the comment from @TheCodeKing, I thought I would take another look at this. It turns out this can be done in a fully documented way while supporting Aero. But it is not for the faint of heart. I will not provide a complete solution here, there are still some kinks to workout, but it does the basics.

This code/solution is based off the Win32 example which can be found at the following location
http://msdn.microsoft.com/en-us/library/bb688195(VS.85).aspx

In principal what you need to do is the following.

  • Extend the client area of the window to cover the Frame. This is done by handling the WM_NCCALCSIZE message and returning 0. This gives the Non-Client area a size of 0 and therefore the client area now covers the entire window.
  • Extend the Frame into the client area using DwmExtendFrameIntoClientArea. This gets the OS to render the Frame over the client area.

The above steps will give you a windows with the standard glass frame excluding the system menu (Window Icon) and the title. The minimize, maximize and close buttons will still be drawn and will work. What you will not be able to do is drag or resize the window, this is because the frame is not really there, remember the client area covers the whole window, we have just asked the OS to draw the frame onto the client area.

Now you can draw on the window as normal, even on top of the frame. You can even put controls in the caption area.

Finally, allow the DWM to handle hit-testing for you, by calling DwmDefWindowProc from your WndProc (before you've processed it). It returns a boolean indicating whether the DWM handled the message for you.

How to add an extra button to the window title bar, so it will be work as standard?

In Vista and Windows 7 there is a new thing called the Desktop Window Manager. This is used to draw the "Aero glass" window titlebars, and do the glow effects. The old Windows XP approach of implementing WM_NCPAINT handlers doesn't work with this new system, so you have to use a whole new API.

I'm sure I've seen some articles on doing what you're asking about, but can't find them right now. Some pages that might give you some leads are:

  • http://msdn.microsoft.com/en-us/magazine/cc163435.aspx

  • http://msdn.microsoft.com/en-us/library/aa969540(v=VS.85).aspx

  • http://delphihaven.wordpress.com/2010/04/19/setting-up-a-custom-titlebar/

How to add a new button in title bar next the minimize button in UWP?

by default UWP does not have the ability to add buttons to the titlebar. But uwp support custom titlebar layout.

For starting hide title bar view

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

After Create new grid layout and attach it to title bar

Window.Current.SetTitleBar(UserLayout);

Create TitleBar and subscribe LayoutMetricsChanged event that uses to dynamically create Margin, because with a different number of system buttons it will be different.

var tBar = CoreApplication.GetCurrentView().TitleBar;
tBar.LayoutMetricsChanged += OnTitleBarLayoutMetricsChanged;

And add function

public void OnTitleBarLayoutMetricsChanged(CoreApplicationViewTitleBar sender, object args)
{
var bar = sender as CoreApplicationViewTitleBar;
RightPanel.Margin = new Thickness(0, 0, bar.SystemOverlayRightInset, 0);
}

Navigate page frame to home page

Content.Navigate(typeof(Home), null, new SuppressNavigationTransitionInfo()); // Navigate to Home page with null args and null animation

End in app.xaml.cs set standart navigation frame to this page

if (e.PrelaunchActivated == false) {
if (rootFrame.Content == null) {
rootFrame.Navigate(typeof(AniMiru.Windows10.Views.AppCustomWindow), e.Arguments);
}
Window.Current.Activate();
}

Page xaml:

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid x:Name="TopBar" >
<Grid x:Name="UserLayout" Background="#00000000" />
<Grid Canvas.ZIndex="1">
<StackPanel x:Name="LeftPanel" Orientation="Horizontal" VerticalAlignment="Stretch" HorizontalAlignment="Left">
<AutoSuggestBox QueryIcon="Find" PlaceholderText="Search" Width="300" />
</StackPanel>
<StackPanel x:Name="RightPanel" Orientation="Horizontal" VerticalAlignment="Stretch" HorizontalAlignment="Right">
<Button Content="" FontFamily="Segoe MDL2 Assets" FontSize="13" VerticalAlignment="Stretch" />
<Button Content="" FontFamily="Segoe MDL2 Assets" FontSize="13" VerticalAlignment="Stretch" />
</StackPanel>
</Grid>
</Grid>
<Grid Grid.Row="1">
<Frame x:Name="Content" />
</Grid>
</Grid>

Page C#:

public AppCustomWindow()
{
this.InitializeComponent();

// Hide titlebar panel and add new layout to title bar
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
Window.Current.SetTitleBar(UserLayout);

// Add LayoutMetricsChanged Event to TitleBar
var tBar = CoreApplication.GetCurrentView().TitleBar;
tBar.LayoutMetricsChanged += OnTitleBarLayoutMetricsChanged;

// Navigate
Content.Navigate(typeof(Home), null, new SuppressNavigationTransitionInfo()); // Navigate to Home page with null args and null animation
}

public void OnTitleBarLayoutMetricsChanged(CoreApplicationViewTitleBar sender, object args)
{
var bar = sender as CoreApplicationViewTitleBar;
RightPanel.Margin = new Thickness(0, 0, bar.SystemOverlayRightInset, 0);
}

Screenshots:

Screenshot

Urls:

Title bar customization

Layout panels

Handling and raising events


Sory for my English.

Best regards.

How can I place a button on the title bar?

Take a look at these 2 links:

Adding caption buttons to the Non-client area on Vista

.Net ActiveButtons Library

It's been a while since I've used VB.Net, so if you don't mind I'll just add a c# code example (basically I took the example from the first link and tried it, it seems to be working fine)

private void Form1_Load(object sender, EventArgs e)
{
IActiveMenu menu = ActiveMenu.GetInstance(this);
ActiveButton button = new ActiveButton();
button.BackColor = Color.LightBlue;
button.Text = "One";
button.Click += button_Click;
menu.Items.Add(button);
}

private void button_Click(object sender, EventArgs e)
{
MessageBox.Show("Button clicked");
}

Note: This button doesn't seem to support transparent background, so it doesn't look quite as good as the button in chrome.

Adding buttons to a Tool Window Title bar

I'm not sure if it can be done more elegantly with pure C#, but normally I use a window with the border style set to none and make my own mock title bar using standard buttons that look like a normal Windows title bar. It's a bit hackey, but when I really need something like this it's the simplest approach.

How to add button to other apps window title bar (XP/Vista)

The standard approach is to inject a DLL into the process with SetWindowsHookEx, hooking WH_CALLWNDPROC to monitor the WM_NCPAINT message. That used to work pretty well but no more. Visual Styles and Vista UAC will make you grow a pretty long beard. Common in the Windows 3.x days, I haven't seen this done in quite a while.

Buttons in window title bar

you should add the attached property "shell:WindowChrome.IsHitTestVisibleInChrome" = true, this should fix your bug.

Add a UserControl in/over titlebar in Window

You can do this by implementing your own title bar.
In order to do so set your window style to none:

WindowStyle="None"

This will mean that the window will have no control box (minimize, maximize, and close buttons) and you will need to implement your own.

You can take a look at the following links to get you started:

http://blog.magnusmontin.net/2013/03/16/how-to-create-a-custom-window-in-wpf/

http://www.codeproject.com/Articles/140267/Create-Custom-Windows-in-WPF-with-Ease

http://www.kirupa.com/blend_wpf/custom_wpf_windows.htm

How can I style the border and title bar of a window in WPF?

Good luck

In Interface builder, how can I add a custom button to a window title bar?

It is not possible to do with Interface Builder, however you can get it done with little bit of coding :

NSButton *closeButton = [window standardWindowButton:NSWindowCloseButton]; // Get the existing close button of the window. Check documentation for the other window buttons.
NSView *titleBarView = closeButton.superview; // Get the view that encloses that standard window buttons.
NSButton *myButton = …; // Create custom button to be added to the title bar.
myButton.frame = …; // Set the appropriate frame for your button. Use titleBarView.bounds to determine the bounding rect of the view that encloses the standard window buttons.
[titleBarView addSubview:myButton]; // Add the custom button to the title bar.


Related Topics



Leave a reply



Submit