Introduction
This article demonstrates a quick and easy-to-use .NET solution for attaching buttons to the non-client area of the window title bar. This uses the ActiveButtons
code library, which is able to preserve the composition and transparency effects in Windows Vista.
Background
The Windows Vista operating system fundamentally changes the way the non-client area is rendered, making it almost impossible (if not actually impossible) to paint onto this area without adversely affecting the look and feel. This is because the new Windows Vista graphics engine renders the non-client area outside of the GDI using the new Desktop Windows Manager (DWM).
The DWM is able to render visual effects such as Aero glass by drawing directly to video memory. In doing this, it allows the system to perform complex blending of content from multiple applications without adversely effecting performance.
The DWM does provide an API for customising the way it renders specific Windows Forms through the use of window attributes and Win32 calls. This provides limited control over the rendering of the non-client areas. For example, in a previous article, I discussed using the DWM API to extend the non-client into a Windows Form to increase the glass surface area. To date, however, there doesn't appear to be a solution for rendering a button cleanly onto the non-client area without losing the visual effects.
In some ways, not being able to draw in the non-client area is a good thing. It leads to cleaner more consistent interfaces and adheres to the recommended Microsoft standards for interface design. That said, sometimes there is a need for more flexibility in application design and a valid argument for making use of the non-client area without losing the standard look & feel. The library discussed in this article provides one possible solution. The alternative would be to paint the entire title bar yourself including the system buttons, or disable composition effects in the application and use the traditional Win32 calls to draw within the NC area.
The Solution
The ActiveButtons
implementation overcomes the limitations of NC rendering in Vista with a unique approach that is not reliant on the DWM API. The solution supports Windows Vista, Windows XP and Windows 2000 from a single codebase, and allows the attachment of buttons to any .NET Windows Form along-side the standard minimise, maximise and close buttons.
Example: Adding Button to Title Bar
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
IActiveMenu menu = ActiveMenu.GetInstance(this);
ActiveButton button = new ActiveButton();
button.BackColor = Color.LightBlue;
button.Text = "One";
button.Click += new EventHandler(button_Click);
menu.Items.Add(button);
}
How It Works
To achieve the desired effect, the library uses some trickery to overlay the buttons onto the windows NC area. This means that the rendering is still preformed within the GDI and the current process, but the DWM still renders the standard title bar complete with any glass and transparency effects where applicable.
To accomplish this, the ActiveMenu
instance creates an additional transparent Windows Form behind the scenes, which is then attached to the original window. This can done from within the constructor as follows:
private ActiveMenu(Form form)
{
...
this.Show(form);
...
}
This new Form is then floated over the title bar area allowing .NET controls to be attached in the usual way. As the DWM treats this as another window, it still blends the buttons and renders them perfectly with the glass background in situ. Once this is achieved, it's just a case of positioning and sizing the buttons correctly. To do this, the menu hooks into the parent Form's Resize
and Move
events, and keeps the child menu correctly positioned.
...
parentForm.SizeChanged += new EventHandler(parent_Refresh);
parentForm.Move += new EventHandler(parent_Refresh);
...
protected void parent_Refresh(object sender, EventArgs e)
{
this.Top = parentForm.Top;
this.Left = parentForm.Left +
parentForm.Width - this.Width -
(SystemInformation.CaptionButtonSize.Width*3) - 2;
}
The approach is fairly radical, so feedback and bug reports are greatly appreciated. Feel free to experiment with the ActiveButtons.dll library in your own applications.
History
- Initial release, Sept 2007
- Additional detail added on how it works, Sept 2007
- Improved demo application and minor bug fixes, Sept 2007
- Added
ActiveButtonsBasic
source code, Sept 2007
- Added compiled help file, Sept 2007
Further Reading