In my efforts to experiment with WPF, I decided to try the always popular WPF sample of an irregular or custom shaped window. I had set out the following goals for this sample:
- Create an oval shaped window with no standard Windows chrome
- Create a context menu that supports minimizing and closing the window
- Support dragging the window when the left mouse button is pressed
Step 1 - Create an oval shaped window with no standard Windows chrome
Searched the web yields a significant amount of results on how to do this, so I am only going to summarize the solution. To accomplish this, you must set the following properties on your window class:
AllowsTransparency="True"
WindowStyle="None"
Background"Transparent"
ResizeMode="CanMinimize"
This will remove the chrome (WindowStyle=“None”), says that the client area supports transparencies (AllowsTransparency=“True”), make the client area transparent (Background=“Transparent”), and only allow minimizing instead of resizing. This means that your window has no borders or control boxes, and the inner area has no default visual background.
{: .float_right} One thing to be careful with, is the Title property. You should still set this as it will allow your application to be identified by the Windows task bar. Further, this application did not show up for me in Windows Task Manager’s Application List (it did show up in the processes list). So be kind to your users and set the Title property on your windows.
Next it is time for the oval window. I chose to use a border control as the root of my client area for this sample. It was the easiest way to get the rounded corners, and the filled background to see the effect. Here is the magic line of code for the rounded shape we want:
<Border CornerRadius="20,20,20,20" Background="Cornsilk"/>
{: .float_right} The actual dimension will be set on the Window class using the Height and Width properties. The border will {: .float_right} just fill it in. Here are screen shots of the window on two different backgrounds. One background is the black of my desktop, and the other is the white of my Windows Life Writer client background.
Step 2 - Create a context menu that supports minimizing and closing the window
The removal of the chrome also removes some standard functionality that users of Windows have come to expect. In this case, the close box and the minimize box. I am excluding the maximize box, because enough users are used to non-resizable windows to understand what not having it means. So, we need to offer our users substitute means of accessing this functionality. Of course the entry in the Windows task bar can do it, but I wanted the user to have it right on the application. I also did not want to add a button and use client real estate to do it. I had opted for no Windows chrome, and not customized chrome for this application.
Given these constraints, I opted for a context menu on the application window. For this sample, I decided to put the context menu directly on the window. In more complex applications, you may want to change that location. Here is the code and resulting context menu: {: .float_right}
<Window.ContextMenu>
<ContextMenu>
<MenuItem Header="Minimize"/>
<MenuItem Header="Exit"/>
</ContextMenu>
</Window.ContextMenu>
Now we need to wire these menu items up to some functionality. WPF, like most Microsoft frameworks, has more than one way to day things. In this case, you chose between traditional events or the command framework. I prefer the command framework when possible, but for this sample I chose to use traditional events and save the commanding framework for another post.
<MenuItem Header="Minimize" Name="mnuMinimize" Click="mnuMinimize_Click"/>
<MenuItem Header="Exit" Name="mnuExit" Click="mnuExit_Click"/>
I assign each menu item a name, not needed, but I like for anything that triggers an event to accessible through code. I also assign a handler to each menu items Click event. Here is the code for those events.
private void mnuExit_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void mnuMinimize_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
Step 3 - Support dragging the window when the left mouse button is pressed
At this point, our little sample application is nearly complete. There is one more piece of functionality to be added – window dragging. I want to add this to only the left mouse button. It turns out that WPF makes this very easy. First we need to add the event trigger to the Window class in the XAML as follows:
MouseDown="Window_MouseDown"
You could have done this in code as well by adding this line in the constructor:
MouseDown +=new MouseButtonEventHandler(Window_MouseDown);
Then you need to add the following code to event handler:
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
DragMove();
}
That is it.
Here is the Window1.xaml source for our solution:
{% gist dbuksbaum/85ad1acaa9c15aa5cecb Window1.xaml %}
Here is the code behind source in Window1.cs:
{% gist dbuksbaum/85ad1acaa9c15aa5cecb Window1.cs %}
Less than 50 lines of code, and we have a fully functioning irregular shaped window that behaves well in the Windows world.