如何在.NET MAUI(Windows)中使用自定义.cur文件作为光标?
我在.NET MAUI Windows应用中尝试使用自定义.cur格式光标文件,切换内置光标(如Hand、Arrow)时功能正常,但加载自定义.cur文件后,光标仅在标题栏变化,主窗口内容区域无变化。
现有可行的内置光标代码
using Microsoft.UI.Input; using Microsoft.UI.Xaml; using Microsoft.Maui.Platform; // 设置内置手型光标示例 var window = (Application.Current.Windows[0].Handler.PlatformView as MauiWinUIWindow); var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window); var cursor = InputSystemCursor.Create(InputSystemCursorShape.Hand); InputCursor inputCursor = cursor; window.CoreWindow.PointerCursor = inputCursor;
尝试的自定义光标代码(未达预期)
using Microsoft.UI.Input; using Microsoft.UI.Xaml; using Microsoft.Maui.Platform; using System.Runtime.InteropServices; public static class CursorHelper { [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern IntPtr LoadCursorFromFile(string filename); [DllImport("user32.dll")] private static extern IntPtr SetCursor(IntPtr hCursor); public static void SetCustomCursor(string filePath) { IntPtr hCursor = LoadCursorFromFile(filePath); if (hCursor != IntPtr.Zero) { SetCursor(hCursor); } } }
调用方式:
CursorHelper.SetCustomCursor("dot.cur");
疑问
- 如何在.NET MAUI Windows应用中正确设置自定义.cur文件作为光标?
- 是否应使用WinUI互操作替代user32.dll?
- 将.cur文件嵌入为资源是否是正确做法?
- 是否需要手动处理PointerMoved事件?
1. 正确设置自定义.cur光标的方法
问题核心是SetCursor仅临时修改光标,WinUI内容区域会自动重置光标状态。正确做法是将自定义光标转换为WinUI的InputCursor对象,再赋值给窗口的CoreWindow.PointerCursor,让框架统一管理整个窗口的光标显示。
2. 优先使用WinUI互操作替代user32.dll
是的,直接基于WinUI API实现更贴合MAUI的WinUI集成逻辑,避免原生API与框架的冲突。可以通过InputCursor.CreateFromPointer将user32加载的光标句柄转换为WinUI兼容的InputCursor,或直接用WinUI的文件加载API读取光标。
3. 将.cur文件嵌入为资源是推荐做法
嵌入资源能避免打包后的文件路径问题,确保应用运行时可稳定访问光标文件。只需将文件的生成操作设为Embedded resource,再通过程序集资源流读取即可。
4. 不需要手动处理PointerMoved事件
只要正确设置CoreWindow.PointerCursor,WinUI框架会自动在整个窗口(包括内容区域)应用光标,无需手动监听指针移动事件。
可运行的完整代码示例
步骤1:配置光标文件
将dot.cur添加到项目(比如Resources文件夹),右键文件→属性:
- 生成操作:
Embedded resource - 复制到输出目录:
如果较新则复制
步骤2:自定义光标帮助类
using Microsoft.UI.Input; using Microsoft.Maui.Platform; using System.IO; using System.Reflection; public static class CustomCursorHelper { public static void SetCustomCursor(string resourceFullName) { var window = Application.Current.Windows[0].Handler.PlatformView as MauiWinUIWindow; if (window == null) return; // 从嵌入资源读取光标流 var assembly = Assembly.GetExecutingAssembly(); using var resourceStream = assembly.GetManifestResourceStream(resourceFullName); if (resourceStream == null) return; // 将流写入临时文件(WinUI需要文件路径加载光标) var tempFilePath = Path.Combine(Path.GetTempPath(), "temp_custom_cursor.cur"); using var fileStream = new FileStream(tempFilePath, FileMode.Create); resourceStream.CopyTo(fileStream); // 加载光标并转换为WinUI InputCursor var cursorHandle = LoadCursorFromFile(tempFilePath); if (cursorHandle != IntPtr.Zero) { var inputCursor = InputCursor.CreateFromPointer(cursorHandle); window.CoreWindow.PointerCursor = inputCursor; } // 清理临时文件 File.Delete(tempFilePath); } [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)] private static extern IntPtr LoadCursorFromFile(string filename); }
步骤3:调用方法
在页面的OnAppearing或按钮点击事件中调用(注意资源名称格式:项目命名空间.文件夹名.文件名.cur):
// 示例:项目命名空间为MauiCursorDemo,光标放在Resources文件夹 CustomCursorHelper.SetCustomCursor("MauiCursorDemo.Resources.dot.cur");
替代方案:直接用WinUI StorageFile加载
如果光标文件设为Content类型(生成操作选Content,复制到输出目录),可直接用WinUI异步API加载:
using Microsoft.UI.Input; using Microsoft.Maui.Platform; using Windows.Storage; public static async Task SetCustomCursorAsync(string relativeFilePath) { var window = Application.Current.Windows[0].Handler.PlatformView as MauiWinUIWindow; if (window == null) return; var fullPath = Path.Combine(AppContext.BaseDirectory, relativeFilePath); var storageFile = await StorageFile.GetFileFromPathAsync(fullPath); var inputCursor = await InputCursor.CreateFromFileAsync(storageFile); window.CoreWindow.PointerCursor = inputCursor; }
调用方式:
await SetCustomCursorAsync("Resources/dot.cur");
内容的提问来源于stack exchange,提问作者Murad Ahmed

