MAUI Blazor自定义标题栏拖动窗口问题:释放鼠标后仍持续移动
MAUI Blazor窗口拖动后释放鼠标仍持续移动的问题解决
你的问题核心是同步阻塞的while循环卡死了UI线程,导致MouseUp事件无法及时更新isDown的状态,循环会一直执行直到资源耗尽或者程序异常。以下是具体的问题分析和修复方案:
问题根源
DragWindow里的while(isDown)是同步执行的,会独占UI线程:
- 鼠标释放时触发的
MouseUp事件因为UI线程被阻塞,无法及时将isDown设为false - 循环没有任何延迟,会高频调用窗口移动API,即使
isDown后续被修改,循环也无法立刻感知
修复方案
将同步循环改为异步执行,同时优化拖动逻辑的精准度:
修改后的ViewModel代码
private bool isDown; private Windows.Graphics.PointInt32 _windowStartPos; private System.Drawing.Point _mouseStartPos; public async void MouseDown() { isDown = true; #if WINDOWS var mauiWindow = App.Current.Windows.First(); var nativeWindow = mauiWindow.Handler.PlatformView; IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow); WindowId windowId = Win32Interop.GetWindowIdFromWindow(windowHandle); AppWindow appWindow = AppWindow.GetFromWindowId(windowId); // 记录拖动起始状态:窗口位置、鼠标位置 _windowStartPos = appWindow.Position; _mouseStartPos = GetCursorPosition(); #endif await DragWindow(); } public void MouseUp() { isDown = false; } private async Task DragWindow() { #if WINDOWS var mauiWindow = App.Current.Windows.First(); var nativeWindow = mauiWindow.Handler.PlatformView; IntPtr windowHandle = WinRT.Interop.WindowNative.GetWindowHandle(nativeWindow); WindowId windowId = Win32Interop.GetWindowIdFromWindow(windowHandle); AppWindow appWindow = AppWindow.GetFromWindowId(windowId); while (isDown) { var currentMousePos = GetCursorPosition(); // 通过偏移量计算新窗口位置,避免固定值导致的拖动错位 int offsetX = currentMousePos.X - _mouseStartPos.X; int offsetY = currentMousePos.Y - _mouseStartPos.Y; appWindow.Move(new Windows.Graphics.PointInt32(_windowStartPos.X + offsetX, _windowStartPos.Y + offsetY)); // 延迟16ms(约60帧/秒),给UI线程留处理事件的时间,同时降低资源消耗 await Task.Delay(16); } #endif } // Win32 API 获取鼠标位置 private System.Drawing.Point GetCursorPosition() { Win32.GetCursorPos(out POINT lpPoint); return new System.Drawing.Point(lpPoint.X, lpPoint.Y); } [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] private struct POINT { public int X; public int Y; } private static class Win32 { [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern bool GetCursorPos(out POINT lpPoint); }
Razor代码(保持不变)
<div @onpointerdown="() => topbarVM.MouseDown()" @onpointerup="() => topbarVM.MouseUp()" class="flex-row fixed-top p-0 m-0"> <!-- 标题栏内容 --> </div>
关键修改点说明
- 异步执行拖动逻辑:用
async/await将拖动循环放到后台执行,避免阻塞UI线程,确保MouseUp事件能及时修改isDown状态 - 精准偏移计算:记录鼠标按下时的窗口和鼠标初始位置,通过偏移量移动窗口,拖动体验更自然
- 添加循环延迟:
Task.Delay(16)既保证拖动流畅性,又让UI线程有机会处理用户输入事件,循环能及时感知isDown的变化
内容的提问来源于stack exchange,提问作者Radzioxo
相关产品推荐
相关产品推荐

