Categories: WPF
Posted by
mheydt on
1/22/2010 11:44 AM |
Comments (0)
Last night I posted about a way to do glass effects in your WPF application. The technique I showed was very basic, just showing how to extend glass into the client area. In a lot of cases, you will want to do a lot more. An example is that it is desireous to put a background image behind the entire window. This would seem to be very straightforward with some XAML as such:
<Window x:Class="SocialBus.Navigator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Hello there" Height="350" Width="525" Icon="Assets/Icons/transparent.png" Background="Transparent">
<Grid>
<Border BorderBrush="Transparent" BorderThickness="0">
<Border.OpacityMask>
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
<GradientStop Offset="1.0" Color="Black" />
<GradientStop Offset="1.0" Color="Transparent" />
</LinearGradientBrush>
</Border.OpacityMask>
<Image Source="Assets/images/pdc09black.png" Stretch="UniformToFill" />
</Border>
</Grid>
</Window>
What this xaml is trying to do is use the pdc09 image as a background, with a linear fade of the opacity from 100% at the bottom to 0% at the top. Unfortuantely, the result is not what I desired, as there is still non-client area on the window that the image is not behind (although I have made the opacity 100% for this image to show the issue better):

The solution to this seems to be involved in intercepting the WM_NCCALCSIZE message to the window, and munging the data to tell the window to have the client area cover the whole window. After many hours of trying to get that to work I just gave up on it and went for another solution.
Another great article on glass effects (chrome) is at this link:
http://blogs.msdn.com/wpfsdk/archive/2008/09/08/custom-window-chrome-in-wpf.aspx
The article itself is quite informative, and states that dealing with the WM_NCCALCSIZE method is not trivial. Fortunately, that writer also has a library that helps out greatly, and you can get it here:
http://code.msdn.microsoft.com/chrome/Release/ProjectReleases.aspx?ReleaseId=1505
I examined this code and it appears very robust, as it handles all kinds of issues with WDM. Nice thing is that it is very easy to use. Just link the DLL into your project, and for the desired effects I just change the XAML to the following:
<Window x:Class="SocialBus.Navigator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ext="clr-namespace:System.Windows.Extensions;assembly=Chrome"
Title="Hello there" Height="350" Width="525" Icon="Assets/Icons/transparent.png" Background="Transparent">
<ext:WindowChrome.WindowChrome>
<ext:WindowChrome
ClientBorderThickness="-1" />
</ext:WindowChrome.WindowChrome>
<Grid>
<Border BorderBrush="Transparent" BorderThickness="0">
<Border.OpacityMask>
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
<GradientStop Offset="1.0" Color="Black" />
<GradientStop Offset="1.0" Color="Transparent" />
</LinearGradientBrush>
</Border.OpacityMask>
<Image Source="Assets/images/pdc09black.png" Stretch="UniformToFill" />
</Border>
</Grid>
</Window>
Note that all I did was add the reference to the DLL and add the one tag, which does a lot of magic in the background configuring the window for custom chrome. The result now is the following:

Perhaps still not quite what I want, but what is going on is that all non-client areas are removed and the image takes up the whole window. With a simple tweak, I can make this much better, by putting the gradient fade back in as well asrounding the corners of the image a little (note, I also changed this a little so that instead of using a border I used a rectangle - border wouldn't clip the image corners round):
<Window x:Class="SocialBus.Navigator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ext="clr-namespace:System.Windows.Extensions;assembly=Chrome"
Title="Hello there" Height="350" Width="525" Icon="Assets/Icons/transparent.png" Background="Transparent">
<ext:WindowChrome.WindowChrome>
<ext:WindowChrome
ClientBorderThickness="-1" />
</ext:WindowChrome.WindowChrome>
<Grid>
<Rectangle RadiusX="10" RadiusY="10">
<Rectangle.Fill>
<ImageBrush ImageSource="Assets/images/pdc09black.png" Stretch="UniformToFill" />
</Rectangle.Fill>
<Rectangle.OpacityMask>
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
<GradientStop Offset="0.0" Color="Black" />
<GradientStop Offset="1.0" Color="Transparent" />
</LinearGradientBrush>
</Rectangle.OpacityMask>
</Rectangle>
</Grid>
</Window>
And the result: just beautiful!

Glass, transparancy of the whole window, and with a custom background. Kewl! And by the way, drag at the top, min, max, close resize on all edges still works perfectly.
There's alot more that can be done with this library, but this is exactly what I ndeeded.
7b998b8f-faf2-461d-aa9f-f5ede3f49d56|0|.0