Saturday, 7 August 2010

Resizable WPF Windows without Minimize and Maximize buttons

When I first started looking at WPF, one of the attractions was the ease with which WPF layout options can be used to create windows with resizable content. I pretty quickly got the idea that resizable windows should be the rule, rather than the exception.

The ability to resize a window is controlled by the Window’s ResizeMode property. When you set ResizeMode to CanResize or CanResizeWithGrip you get a window that can be resized. You also get minimize and maximize buttons in the window’s title bar.

Setting a Window’s WindowStyle property to ToolWindow creates a window with a thin title bar, a close button and no minimized or maximize buttons. However, (in addition to looking a bit odd) this still allows access to the minimize and maximize commands from the system menu:

 toolwindow

WPF’s Window class does not provide any way to create a resizable window that cannot be minimized.

You might think that’s fair enough for a top level window, but it’s not so good for secondary windows, especially modal dialogs.

Modal dialogs should never minimize. When a modal dialog is displayed, the owner window is disabled until the dialog is closed. If the modal dialog is minimized, the owner window remains disabled – to the user it looks like the application just locked up.

The Solution

WPF windows are just like any other as far as the operating system is concerned. The window’s title bar and borders are provided by the operating system. When you set the WindowStyle and ResizeMode properties, WPF uses the SetWindowLong Windows API call to modify the style and extended style flags for the window.

As far as the operating system is concerned, the appearance of the minimize and maximize buttons is controlled by the WS_MINIMIZEBOX and WS_MAXIMIZEBOX flags in the window style. If we want to control the appearance of these buttons for ourselves, we can set and clear these two flags with a combination of calls to the GetWindowLong and SetWindowLong functions.

To implement this behaviour, I created the ExtraWindowStyles class. This class provides attached properties CanMinimize and CanMaximize which can be applied to a window to hide (or show) the minimize and maximize buttons.

Example usage:

<Window x:Class="ExtraWindowStyles.TestWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ews="clr-namespace:ExtraWindowStyles"
    Title="TestWindow"
    ResizeMode="CanResizeWithGrip"
    ews:ExtraWindowStyles.CanMinimize="false" 
    ews:ExtraWindowStyles.CanMaximize="false" 
    Height="300" 
    Width="300"
>

testwindow

Implementing this behaviour using attached properties makes it straightforward to use with styles:

<Style x:Key="myDialogStyle" TargetType="Window">
    <Setter Property="ews:ExtraWindowStyles.CanMinimize" 
            Value="false" 
    />
    <Setter Property="ews:ExtraWindowStyles.CanMaximize" 
            Value="false" 
    />
</Style>

Download the source here: ExtraWindowStyles.cs

Thursday, 17 June 2010

Data binding to Fields with a DynamicObject Proxy

WPF data binding only works with properties, not fields. If you have an existing type with fields that you want to bind to, you need some kind of wrapper to expose the fields as properties. That can lead to a lot of replication, wouldn’t it be nice if there was an automatic way to do this?

Enter FieldToPropertyProxy. This class is a slight variation on my previous post, again derived from DynamicObject.

The implementation is almost identical to NotifyPropertyChangedProxy, except that references to GetProperty and PropertyInfo are replaced with GetField and FieldInfo.

As well as converting fields into properties, NotifyPropertyChangedProxy includes an implementation of INotifyPropertyChanged.

Download the code here: FieldToPropertyProxy.cs

Tuesday, 8 June 2010

Automatic INotifyPropertyChanged with DynamicObject

Implementing the INotifyPropertyChanged interface is Microsoft’s recommended mechanism for providing notifications to update WPF data bindings.

Normally, I like to use my code snippets to implement INotifyPropertyChanged on classes I’m writing, but what if I want to use data binding on a class that I didn’t write and which doesn’t support INotifyPropertyChanged?

In this post, I show how to use the DynamicObject class introduced in .Net 4 to create a proxy that wraps access to another object’s properties while adding automatic support for INotifyPropertyChanged.

Wednesday, 2 June 2010

Snoop is on CodePlex

Snoop is an essential tool for understanding and debugging WPF applications.

snoop

Originally created by Pete Blois, Snoop is now maintained by Cory Plott, who has made it available on CodePlex, and added WPF 4.0 compatibility.

Simply put, Snoop displays the visual tree of a running WPF application in the left pane, and the properties of the selected element in the right pane. Read a more detailed description from Pete Blois at http://blois.us/Snoop/

Download the latest Snoop from http://snoopwpf.codeplex.com/releases

Wednesday, 3 March 2010

Four Free XAML Editors Reviewed

I like to type XAML.

It’s an extremely flexible and expressive way to work when sketching out the logical structure of a new piece of UI.

A graphical design tool like Blend is best for some things, like creating a non-trivial gradient brush, but at some point it all comes down to the code.

To satisfy my need for speed and create a sense of flow I need a fast editor that can provide instant feedback.

XAML editors exist on a continuum from the fast and lightweight to the more powerful but cumbersome. The professional tools (Visual Studio and Blend) occupy the heavyweight end, but there are also a number of free tools that provide a more basic but responsive experience.

In this post, I’ll look in detail at four free XAML editors all of which are quick to start up and responsive as you type.