dotnet/wpf · error · InvalidOperationException
SR.DragMoveFail
Error message
SR.DragMoveFail
What it means
Window.DragMove initiates a mouse-drag window move by sending WM_SYSCOMMAND/SC_MOUSEMOVE, which is only valid while the left mouse button is down. If DragMove is called when the mouse's left button is not pressed (or outside a valid drag context), WPF throws this InvalidOperationException (SR.DragMoveFail).
Solutions
- Call DragMove only inside a MouseLeftButtonDown event handler, synchronously
- Do not defer the call with Dispatcher.BeginInvoke or async continuations
- Verify Mouse.LeftButton == MouseButtonState.Pressed before calling DragMove
- For button-click initiated drags, capture mouse on down and call DragMove on the down event instead
Example fix
// before
private void TitleBar_Click(object sender, RoutedEventArgs e) {
DragMove(); // throws: left button not down
}
// after
private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
if (Mouse.LeftButton == MouseButtonState.Pressed) {
DragMove();
}
} Defensive patterns
Strategy: validation
Validate before calling
if (e is MouseButtonEventArgs mbe && mbe.ChangedButton == MouseButton.Left && Mouse.LeftButton == MouseButtonState.Pressed) { DragMove(); } Type guard
bool CanDragMove() => Mouse.LeftButton == MouseButtonState.Pressed;
Try / catch
try { DragMove(); } catch (InvalidOperationException ex) when (ex.Message == SR.DragMoveFail) { /* ignore: not in drag state */ } Prevention
- Wire DragMove to MouseLeftButtonDown only
- Never defer DragMove via Dispatcher or async
- Check Mouse.LeftButton state before the call
When it happens
Trigger: Calling window.DragMove() outside of a MouseLeftButtonDown handler (e.g. from a Click event, a timer, or before the left button is pressed), or calling it after the mouse-up already occurred.
Common situations: Implementing custom chrome/borderless windows and wiring DragMove to MouseLeftButtonUp or a button click instead of MouseLeftButtonDown; calling DragMove asynchronously (Dispatcher.BeginInvoke) after the button state changed; simulating drag on touch without mouse capture.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- InvalidEnumArgumentException("actions", (int)actions…
- InvalidEnumArgumentException("button", (int)button…
- InvalidEnumArgumentException("captureMode"…
- SR.CannotSetOwnerToItself
- SR.CantSetOwnerAfterDialogIsShown
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/5a5d5d551548e4ca.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs:257
return;
}
// Mouse.LeftButton actually reflects the primary button user is using.
// So we don't need to check whether the button has been swapped here.
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
if (WindowState == WindowState.Normal)
{
// SendMessage's return value is dependent on the message send. WM_SYSCOMMAND
// and WM_LBUTTONUP return value just signify whether the WndProc handled the
// message or not, so they are not interesting
UnsafeNativeMethods.SendMessage( Handle, WindowMessage.WM_SYSCOMMAND, (IntPtr)NativeMethods.SC_MOUSEMOVE, IntPtr.Zero);
UnsafeNativeMethods.SendMessage( Handle, WindowMessage.WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
}
}
else
{
throw new InvalidOperationException(SR.DragMoveFail);
}
}
/// <summary>
/// Shows the window as a modal window
/// </summary>
/// <returns>bool?</returns>
/// <remarks>
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
/// </remarks>
public Nullable<bool> ShowDialog()
{
// this call ends up throwing an exception if ShowDialog
// is not allowed
VerifyApiSupported();
VerifyContextAndObjectState();
VerifyCanShow();
VerifyNotClosing();View on GitHub (pinned to 81131a70a4)