5

To implement docking I was relying on listening to the Window.LocationChanged event to detect the changing position of a window being dragged around the screen. But a user reported that docking was not working on their machine.

Turns out they had disabled "Show window contents while dragging" in Windows performance options and as a result the LocationChanged event is only fired once the window is moved to it's final position, not while the window is in mid-flight.

I was wondering if there was an alternative way to detect window moves, a nice way. I know I could pinvoke, or wire up some horrific timer, but I was hoping for a better way, perhaps there is a reliable event to listen on?

Here's a method to forestall any "you didn't post any code"/"what have you tried" complaints.

protected override void OnLocationChanged(EventArgs e)
{

}
Weyland Yutani
  • 4,682
  • 1
  • 22
  • 28
  • I'm not aware of any WPF API to detect when a window is moving under these circumstances. `[Preview]MouseMove` does not fire when the mouse is over the non-client area, and as you have observed, `LocationChanged` only fires while dragging if "show window contents while dragging" is toggled. You'll probably have to do some p/invoke or, alternatively, draw your own window chrome (but even that may not work if you call `DragMove` to handle window dragging). Also, checking the mouse state doesn't cover all window movement--you can initiate and complete window relocation using only the keyboard. – Mike Strobel Nov 10 '14 at 15:41
  • ***I know I could pinvoke*** so just do it this way. I don't think there is something better here. Also pinvoke is not something bad, it's in fact sometimes the only solution you have. – King King Nov 10 '14 at 16:35

1 Answers1

3

Here's my solution,

Excellent work.

class MyWindow : Window
{
    private const int WM_MOVING = 0x0216;
    private HwndSource _hwndSrc;
    private HwndSourceHook _hwndSrcHook;

    public MyWindow()
    {
        Loaded += OnLoaded;
        Unloaded += OnUnloaded;
    }

    void OnUnloaded(object sender, RoutedEventArgs e)
    {
        _hwndSrc.RemoveHook(_hwndSrcHook);
        _hwndSrc.Dispose();
        _hwndSrc = null;
    }

    void OnLoaded(object sender, RoutedEventArgs e)
    {
        _hwndSrc = HwndSource.FromDependencyObject(this) as HwndSource;
        _hwndSrcHook = FilterMessage;
        _hwndSrc.AddHook(_hwndSrcHook);
    }

    private IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        switch (msg)
        {
            case WM_MOVING:
                OnLocationChange();
                break;
        }

        return IntPtr.Zero;
    }

    private void OnLocationChange()
    {
        //Do something
    }
}