Click here to Skip to main content
15,883,623 members
Articles / Desktop Programming / WPF
Article

WPF Window Resizing

Rate me:
Please Sign up or sign in to vote.
3.86/5 (16 votes)
23 Jan 2008CPOL4 min read 163.2K   6.5K   37   23
An article on using UI elements to control window size
windowresize1.jpg

windowresize2.jpg

Introduction

In certain cases it may be desirable to completely replace the non-client area (title bar, title bar buttons and window borders) with a completely custom user interface. An example of such is when applying buttons that seemingly cross from non-client areas to client areas (e.g. the Start button found in Microsoft Office 2007 applications such as Microsoft Office Word). In these instances, a Windows Presentation Foundation (WPF) window may be created using no client area and the entire window recreated, gaining access to all areas of the new window as a client area.

Standard window functionality must be recreated for the user experience to remain constant. Most functionality (i.e. window move, close, maximise, restore, minimise) is easily achieved. However, window resizing by mouse drag is considerably more complex.

In this article, an approach to creating resizable windows with the standard resize drag functionality is presented. A utility library is provided which allows any WPF window to be resized via UIElements (not necessarily part of the window to be resized). The mouse pointer is adjusted to the relevant graphic automatically when the pointer is hovering over any registered window resizing control.

Using the Code

A single class called WindowResizer is included in the library, which controls all functionality to do with resizing. To use the library, it should be included and linked into the UI as follows. Note that an ideal place is the constructor for the window since, in most cases, the resize components will be available from window birth to death.

C#
//this is the target window object for resizing
WindowResizer wr = new WindowResizer(this);

//xxxSizeGrip, where xxx corresponds to the equivilent border position
wr.addResizerRight(rightSizeGrip);
wr.addResizerLeft(leftSizeGrip);
wr.addResizerUp(topSizeGrip);
wr.addResizerDown(bottomSizeGrip);
wr.addResizerLeftUp(topLeftSizeGrip);
wr.addResizerRightUp(topRightSizeGrip);
wr.addResizerLeftDown(bottomLeftSizeGrip);
wr.addResizerRightDown(bottomRightSizeGrip);

During the call to .addResizer...(UIElement), all event handler hooks are added to the UI element. From call completion, the component will be acting as a resizing element upon the target window. The window and elements must be valid and created before the calls are made.

Two event handlers are added to each UI element to control the pointer graphic (i.e. to achieve the arrow graphics while hovering the border), MouseEnter and MouseLeave. In this release, this option is sufficient. However, in later releases this will be changed to an unmanaged call to the underlying Windows APIs to prevent the pointer changing back to the standard arrow pointer when rapidly sizing the window up. By increasing the mouse polling speed (and hence making the resize operations more rapidly starting) this effect is reduced, although it is noticeable. A starting point for research to solve this effect would be investigation of user32.dll.

This problem is made significantly complex due to the different handling of mouse move events and mouse positioning. Under .NET 2.0, Cursor.GetPosition(...) returned the position of the mouse relative to the specified component. However, under .NET 3.5, this has changed to the position of the mouse relative to the component, but clamped to the bounds of the component. For example, given that a component has a horizontal screen position of 100 pixels, a width of 200 pixels and a mouse screen position of 500 pixels, .NET 2.0 would return a relative position to the component of 400 pixels. However, .NET 3.5 returns a relative position of just 200 pixels.

A similar effect is found when using Cursor.GetPosition(...). The returned value is clamped to the relative bounds of the component. The solution to this is to get the absolute screen position via a user32.dll call. Specifically, the following code must be added and polled routinely (20 millisecond delay between polls) while dragging the mouse:

C#
[DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetCursorPos(out PointAPI lpPoint);

private struct PointAPI
        {
            public int X;
            public int Y;
        }

The GetCursorPos() method is polled via the following call:

C#
PointAPI p = new PointAPI();
GetCursorPos(out p);

Using user32.dll is just one way of obtaining mouse position data outside the bounds of a WPF window. It is possible to use DirectInput and obtain a Microsoft.DirectX.DirectInput.Device. However, the mouse position is not reported rather than the mouse movement (i.e. 2 right, 10 down). Extreme care must be taken when using this form of input, as the position data generated may not correspond to the same resolution as the screen (i.e. 10 right from DirectInput may not correspond to 10 screen pixels right).

Points of Interest

All other window functionality is easily implemented and mostly a case of using Grid layout to position correctly. A close button is implemented via a button click handler and Window.Close(). Maximise, restore and minimise are implemented via Window.WindowState, and window dragging is implemented via MoveDrag() on the MouseDown or MouseLeftButtonDown UIElement handler. Curiously, no ResizeDrag() is available currently.

History

Version 1.0.0.0 (January 23, 2008) Basic mouse drag functionality with auto cursor icon changing.

Contributors

Grateful thanks to Mike for his work on user32.dll.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Rail Research UK
United Kingdom United Kingdom
I originally studied for a masters in engineering of software engineering at The University of Birmingham during 2000-2004, of which I received a 2:1. I continued at Birmingham University working with Civil Engineering and Rail Research UK where I am currently in my final year of a 3 year PhD project developing a Computational Intelligent Approach to Railway Intervention Planning. Although my work has a significant focus on railway engineering and associated practices much of my work is with data mining (on SQL Server 2008) and computational intelligence (CI) techniques. My key areas of expertise in CI are clustering algorithms (including Rival Penalised Competitive Learning) and evolutionary algorithms.

Outside of my formal work I enjoy testing the latest technologies such as .NET 3.5 and the many frameworks of which it comprises (mainly WPF). I have several projects on the go including a .NET and DirectX port of Quake 3 and many utility libraries. I also maintain an extensive website coded in Cold Fusion which is regularly updated; more information is available about me there.

Comments and Discussions

 
QuestionMove resizing window for WindowStyle="None" Pin
Flashan200223-May-13 21:12
Flashan200223-May-13 21:12 
AnswerChange suggestion Pin
Martin HuHn1-Aug-11 3:57
Martin HuHn1-Aug-11 3:57 
GeneralMy vote of 3 Pin
StewBob2-Nov-10 8:20
StewBob2-Nov-10 8:20 
GeneralNice Resizer Pin
Member 429695221-Oct-10 22:17
Member 429695221-Oct-10 22:17 
GeneralA resize megamix! Pin
jp chow8-May-09 10:58
jp chow8-May-09 10:58 
GeneralRebuilt and this doesn't work right Pin
CynisterSix3-Apr-09 11:47
CynisterSix3-Apr-09 11:47 
GeneralThere's built-in functionality Pin
Stanislav Kniazev30-Dec-08 4:42
Stanislav Kniazev30-Dec-08 4:42 
GeneralRe: There's built-in functionality Pin
CynisterSix3-Apr-09 12:20
CynisterSix3-Apr-09 12:20 
GeneralRe: There's built-in functionality Pin
Stanislav Kniazev3-Apr-09 23:59
Stanislav Kniazev3-Apr-09 23:59 
GeneralRe: There's built-in functionality Pin
Eshva8-Feb-10 3:24
Eshva8-Feb-10 3:24 
GeneralMy version of Stanislav's solution Pin
Eshva8-Feb-10 3:44
Eshva8-Feb-10 3:44 
GeneralRe: My version of Stanislav's solution Pin
M0nsign0r16-Nov-11 4:01
M0nsign0r16-Nov-11 4:01 
GeneralMy vote of 2 Pin
Jared Thirsk12-Dec-08 18:26
Jared Thirsk12-Dec-08 18:26 
GeneralMy vote of 1 Pin
Stanislav Kniazev24-Nov-08 2:35
Stanislav Kniazev24-Nov-08 2:35 
QuestionCan this be applied to Listbox Item Pin
anjali Batra19-Sep-08 2:00
anjali Batra19-Sep-08 2:00 
AnswerRe: Can this be applied to Listbox Item Pin
Derek Bartram19-Sep-08 2:10
Derek Bartram19-Sep-08 2:10 
GeneralCrashes when resizing using the top left corner Pin
daveoggy19-Jun-08 6:13
daveoggy19-Jun-08 6:13 
GeneralRe: Crashes when resizing using the top left corner Pin
Derek Bartram20-Jun-08 2:07
Derek Bartram20-Jun-08 2:07 
GeneralRe: Crashes when resizing using the top left corner Pin
Jonathan Schmidt3-Oct-10 3:43
Jonathan Schmidt3-Oct-10 3:43 
Generalchoppy resize Pin
S. Ryan30-Jan-08 4:42
S. Ryan30-Jan-08 4:42 
GeneralRe: choppy resize Pin
Derek Bartram30-Jan-08 16:33
Derek Bartram30-Jan-08 16:33 
GeneralRe: choppy resize Pin
Derek Bartram4-Feb-08 13:45
Derek Bartram4-Feb-08 13:45 
GeneralRe: choppy resize Pin
Derek Bartram22-Mar-08 10:47
Derek Bartram22-Mar-08 10:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.