Introduction
Windows Vista has a new default theme called Aero glass. In Aero glass, the title bar of a window and the frame is drawn transculent. This gives the UI a clean and lightweight look. This nice feaure is provided by a service that is called the desktop window manager (DWM).
Extending the Glass
By default the blurry glass effect is only on the title bar and the frame, but the client area is drawn opaque. But there is a simple way to extend the glass into the client area by using the DWM's API.
First thing you need to do is to include some Win32 functions from the
dwmapi.dll
library.
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows;
[StructLayout(LayoutKind.Sequential)]
struct MARGINS
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
[DllImport("dwmapi.dll")]
static extern int
DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
[DllImport("dwmapi.dll")]
extern static int DwmIsCompositionEnabled(ref int en);
/// Extends the glass area into the client area of the window
/// </summary>
/// <param name="window"></param>
/// <param name="top"></param>
public static void ExtendGlass(Window window, Thickness thikness)
int isGlassEnabled = 0;
DwmIsCompositionEnabled(ref isGlassEnabled);
if (Environment.OSVersion.Version.Major > 5 && isGlassEnabled > 0)
// Get the window handle
WindowInteropHelper helper =
new
WindowInteropHelper(window);
HwndSource mainWindowSrc = (HwndSource)HwndSource.
FromHwnd(helper.Handle);
mainWindowSrc.CompositionTarget.BackgroundColor =
Colors.Transparent;
// Get the dpi of the screen
System.Drawing.Graphics desktop =
System.Drawing.Graphics.FromHwnd(mainWindowSrc.Handle);
float dpiX = desktop.DpiX / 96;
float dpiY = desktop.DpiY / 96;
// Set Margins
MARGINS margins =
new
MARGINS();
margins.cxLeftWidth = (int)(thikness.Left * dpiX);
margins.cxRightWidth = (int)(thikness.Right * dpiX);
margins.cyBottomHeight = (int)(thikness.Bottom * dpiY);
margins.cyTopHeight = (int)(thikness.Top * dpiY);
window.Background = Brushes.Transparent;
int hr = DwmExtendFrameIntoClientArea(mainWindowSrc.Handle,
ref margins);
window.Background = SystemColors.WindowBrush;
catch (DllNotFoundException)
Next thing you need to do is calling the
ExtendGlass
in the
OnSourceInitialized
callback. Because that is the time the window handle has been created.
protected override void OnSourceInitialized(EventArgs e)
base.OnSourceInitialized(e);
GlassHelper.ExtendGlass(this, LayoutRoot.Margin);
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam,
IntPtr lParam, ref bool handled)
if (msg == GlassHelper.WM_DWMCOMPOSITIONCHANGED)
GlassHelper.ExtendGlass(this, LayoutRoot.Margin);
handled = true;
return IntPtr.Zero;
Hi Tim,
The System.Drawing namespace is defined in a separate assembly called "System.Drawing". You probably forgot to add a reference to that assembly. In Blend it's a bit tricky to do this. But in Visual Studio just right-click of the "References" folder in your project and choose "Add Reference..." then select the tab ".NET" and find the "System.Drawing" entry.
I hope this helps.
Greetings
Christian
Thanks-- I'm still a bit new to C#, and my experience with Java isn't helping much at times like this :) Thanks for the tip-- I will be sure to make use of it.
By the way, do you know if there's a way to render text with the Vista/Win7 blur behind it? That is, the effect used on the gadget list when you try to add to the sidebar/desktop, or in the titlebar of a window? I've read about this for doing straight-up C/++ application programming, but I don't know if there is a way to specify such things given the interface that Blend gives you. And it would be slightly backwards if I had to programatically render the text instead of using the xaml/gui editor.
If not, I can live with it :P (or fake the effect, either way!) Thanks muchly for sharing your expertise.
Implementation in VB.NET:
Imports System.Drawing
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("dwmapi.dll", CharSet:=CharSet.Auto)> _
Public Shared Sub DwmExtendFrameIntoClientArea(ByVal hWnd As System.IntPtr, ByRef pMargins As Printing.Margins)
End Sub
Private Glass_brush As SolidBrush = New SolidBrush(Color.Black)
Private border_extensions As Printing.Margins = New Printing.Margins
'Public Structure Margins
' Public Left As Integer
' Public Right As Integer
' Public Top As Integer
' Public Bottom As Integer
'End Structure
Public Sub New()
InitializeComponent()
border_extensions.Top = 300 'amount of border extension required from top border
border_extensions.Left = 300 'amount of border extension required from left border
border_extensions.Right = 300 'amount of border extension required from right border
border_extensions.Bottom = 300 'amount of border extension required from the bottom border
DwmExtendFrameIntoClientArea(Me.Handle, border_extensions)
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
e.Graphics.FillRectangle(Glass_brush, New System.Drawing.Rectangle(0, 0, 300, 300))
'' painting the areas in client regions in black..if these fall in the margins described u would get
'' glass effect!
End Sub
End Class
It seems overkill to do anything based just plainly on operating system such as vista. I work at a massive organisation and they wouldn't touch it. I havent used it so no comment, i like the glass effect. But seriously solutions should and need to be for XP and above, not just for vista. home users use vista organisations tend to stay away. And thats a fact. Why have a nice window that looks crap when majority of users use it.
Fixed the buttons. I changed the color from black to navy and used a pannel to get the aero feel. I just want to know is there a way that the icons displayed in a listview can be full scale? when i set it to 32x32 they look very bad, can it be that the icons look like vista desktop icons? with that kind of select effect?
Fixed the buttons. I changed the color from black to navy and used a pannel to get the aero feel. I just want to know is there a way that the icons displayed in a listview can be full scale? when i set it to 32x32 they look very bad, can it be that the icons look like vista desktop icons? with that kind of select effect?
Hi Christian, thanks for a great tutorial. It works beautifully but I'm curious, just how does this look on XP? Also, I was wondering if you know a technique to also extend the ability to drag a window by clicking on the title bar over the entire new glass region. Even though the glass looks seamless I am still only able to drag a window by the region up at the top.
There are a couple of lines of code missing in your example to make it perfect.
First:
public const int WM_DWMCOMPOSITIONCHANGED = 0x031E;
needs to be declared in the GlassHelper class.
Secondly:
In order for the WndProc procedure to run in WPF the following lines should be added to the windows load event since WPF windows don't have a hWnd
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
Otherwise the example is a nice one.