You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Blazor Hybrid应用中检测窗口移动事件?

在Windows平台的Blazor Hybrid应用中检测窗口移动事件

你可以通过两种方式实现Windows平台下的窗口移动检测,一种是利用MAUI官方修复后的API,另一种是直接使用Win32底层窗口消息监听:

方法1:基于MAUI AppWindow的消息监听

由于你提到的相关GitHub问题已修复,现在可以通过Microsoft.UI.Windowing.AppWindow的消息事件捕获窗口移动信号。核心思路是监听Win32的WM_MOVE消息,该消息会在窗口位置改变时触发。

#if WINDOWS
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
#endif

// 获取当前MAUI窗口实例
var currentMauiWindow = Application.Current.Windows.First();

#if WINDOWS
// 转换为WinUI窗口,获取对应的AppWindow
var winuiWindow = currentMauiWindow.Handler.PlatformView as Window;
var appWindow = AppWindow.GetFromWindowId(winuiWindow.WindowId);

// 监听窗口消息
appWindow.WindowMessageReceived += (sender, args) =>
{
    const uint WM_MOVE = 0x0003;
    if (args.Message.MessageId == WM_MOVE)
    {
        // 获取最新窗口位置
        var windowPosition = appWindow.Position;
        // 这里添加你的移动后处理逻辑
        Console.WriteLine($"窗口已移动至:X={windowPosition.X}, Y={windowPosition.Y}");
    }
};
#endif

方法2:Win32底层窗口过程钩子

如果需要更灵活的控制,可直接通过Win32API替换窗口过程,监听WM_MOVE或WM_WINDOWPOSCHANGED消息(后者会在窗口大小、位置改变时触发)。

#if WINDOWS
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
using System.Runtime.InteropServices;
#endif

private nint _originalWndProc;

// 初始化钩子
public void SetupWindowMoveListener()
{
#if WINDOWS
    var currentMauiWindow = Application.Current.Windows.First();
    // 获取窗口句柄
    var hwnd = new HWND((nint)currentMauiWindow.Handler.PlatformView.GetType()
        .GetProperty("WindowHandle")
        .GetValue(currentMauiWindow.Handler.PlatformView));

    // 替换窗口过程
    _originalWndProc = PInvoke.SetWindowLongPtr(hwnd, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, 
        (nint)Marshal.GetFunctionPointerForDelegate(new WNDPROC(CustomWndProc)));
#endif
}

// 自定义窗口过程
private nint CustomWndProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam)
{
    const uint WM_MOVE = 0x0003;
    const uint WM_WINDOWPOSCHANGED = 0x0047;

    if (msg == WM_MOVE || msg == WM_WINDOWPOSCHANGED)
    {
        RECT windowRect = new();
        PInvoke.GetWindowRect(hwnd, ref windowRect);
        Console.WriteLine($"窗口位置更新:X={windowRect.left}, Y={windowRect.top}");
    }

    // 调用原始窗口过程,保证窗口正常运作
    return PInvoke.CallWindowProc(_originalWndProc, hwnd, msg, wParam, lParam);
}

// 窗口关闭时恢复原始窗口过程,避免内存泄漏
public void CleanupWindowListener()
{
#if WINDOWS
    var currentMauiWindow = Application.Current.Windows.First();
    var hwnd = new HWND((nint)currentMauiWindow.Handler.PlatformView.GetType()
        .GetProperty("WindowHandle")
        .GetValue(currentMauiWindow.Handler.PlatformView));
    
    PInvoke.SetWindowLongPtr(hwnd, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, _originalWndProc);
#endif
}

关于WebView2的关联说明

Tauri的onMoved事件本质也是通过监听Win32窗口消息实现的,和上述两种方案的核心逻辑一致,都是捕获窗口移动相关的系统消息来触发事件回调。

内容的提问来源于stack exchange,提问作者VassilisM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 04:18:20