WPF: Window Dock Behavior


**updated this post for Blend 3 RC release

Have you ever used WinSplit Revolution? It’s a utility that helps you organize your windows into regions to assist with organizing your screen real estate. I find this to be a very useful tool, especially when I use two monitors while doing development, being able to organize my windows neatly makes a huge difference. One cool feature is called Drag’n’Go. When you drag your window outside your screen boundary, a semi-transparent rectangle (I’d like to call it an overlay) appears to cue you on the location of where the window will be docked. I really like this feature, and wondered how difficult it would be to incorporate this into a Behavior for a Window class in WPF to exhibit the same kind of functionality. Here’s my result.

DockWindow

As you can see from the screenshot, when you move the window to the right outside of the desktop area, an overlay appears to that “inform” you that the window will be docked to the right half when you let go of the mouse click. I’ve create 8 different positions for this, which are BottomRight, Right, TopRight, Top, TopLeft, Left, BottomLeft, and Bottom.

The semi-transparent blue rectangle overlay you see is basically another Window instance, and triggered just by using the Show() method. To get that effect, I basically set some properties on the Window overlay.

_overlay = new Window()
{
AllowsTransparency = true,
Opacity = 0.5,
WindowStyle = WindowStyle.None,
ShowActivated = false,
ResizeMode = ResizeMode.NoResize,
Background = Brushes.LightBlue,
ShowInTaskbar = false
};

When the Application Window gets dragged to different locations, I check for boundary limits and update the overlay with new layout position and size. The only problem I had was with the LocationChanged event in the Window class. When a user drags/minimize/maximize/resizes the Window, LocationChanged is fired. However I had no way to determine if the use is actually still holding the the left mouse button (which is true when you drag) because during dragging the Mouse Button events do not fire. I had to find another approach.

  1. Use a timer which will start or reset when LocationChanged is fired. (I used a DispatcherTimer and set interval to 200 milliseconds)
  2. When timer interval elapsed, check if mouse is up or down. Use Win32 API for this, using GetAsyncKeyState(int key) from user32.dll.
  3. if mouse is down, check if Window overlaps boundary. If true, show overlay, else hide it.
  4. if mouse is up, update Window’s location and size if overlay was visible, else do nothing.
  5. Wire up Window SizeChanged and StateChanged events, and stop timer in these events. We don’t have to exhibit the behavior when user is resizing or minimizing/maximizing the window.

I hope the above steps I took makes some sense. Anyways, here’s cut-down snippet of the above steps.

private DispatcherTimer _timer;

[DllImport(“user32.dll”)]
static extern short GetAsyncKeyState(int vKey);
private const int VK_LBUTTON = 0x01;

public DockWindowBehavior()
{
_timer = new DispatcherTimer(TimeSpan.FromMilliseconds(200), DispatcherPriority.Normal, Poll, this.Dispatcher);
_timer.Stop();
}

protected override void OnAttached()
{
this.AssociatedObject.LocationChanged += new EventHandler(AssociatedObject_LocationChanged);
this.AssociatedObject.SizeChanged += new SizeChangedEventHandler(AssociatedObject_SizeChanged);
this.AssociatedObject.StateChanged += new EventHandler(AssociatedObject_StateChanged);
}

void AssociatedObject_StateChanged(object sender, EventArgs e)
{
_timer.Stop();
}

void AssociatedObject_SizeChanged(object sender, SizeChangedEventArgs e)
{
_timer.Stop();
}

void AssociatedObject_LocationChanged(object sender, EventArgs e)
{
_timer.Stop();
_timer.Start();
}

private void Poll(object sender, EventArgs e)
{
bool isMouseDown = GetAsyncKeyState(VK_LBUTTON) < 0; if (isMouseDown) { // if window overlaps boundary, show overlap, else hide it } else { // if overlap is visible, set window's new position and size } } [/sourcecode] So what's the point of having such a behavior? Well...mainly for the fun of it I guess. And you never know, as business requirements come in various shape and form, you might just end up needing something like this in a business application. Download this code sample here. (updated this sample to work with Blend 3 RC)

Share this post:
Advertisements
Posted in WPF. Tags: . 2 Comments »

2 Responses to “WPF: Window Dock Behavior”

  1. Carl Weis Says:

    This is really cool.

    How do I use it within expression blend, or visual studio?

    Great Work!

    • Ed Foh Says:

      Hi Carl,

      thanks! It’s a behavior you can attach to a Window control in your XAML code. Once the behavior is attached to any window element, it will have that docking functionality.

      Ed


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: