UWP/C# 实现跟随光标进度环的技术咨询
我之前也碰到过这个需求,UWP里确实没有直接把Progress Ring绑定到光标上的现成API,不过有两种可行的方案,我给你详细说说:
方案一:使用覆盖层+Progress Ring(推荐,简单易实现)
这种方法是在等待新窗口启动的过程中,在当前页面上方盖一个半透明的加载层,里面放Progress Ring,既可以提示用户正在加载,还能阻止用户误操作底层控件,实现起来非常直观。
步骤1:在页面XAML中添加加载覆盖层
把这个覆盖层放在页面的根容器最上层(确保能盖住所有内容):
<Grid> <!-- 这里是你原有的页面内容 --> <!-- 加载覆盖层,默认隐藏 --> <Grid x:Name="LoadingOverlay" Background="#7F000000" <!-- 半透明黑色背景 --> Visibility="Collapsed" IsHitTestVisible="True"> <!-- 拦截点击事件,防止操作底层控件 --> <ProgressRing x:Name="LoadingRing" IsActive="True" Width="60" Height="60" Foreground="White"/> </Grid> </Grid>
步骤2:在启动新窗口的代码中控制覆盖层显示/隐藏
用try-finally确保不管新窗口启动成功还是失败,覆盖层都会被隐藏:
private async void OpenNewWindowButton_Click(object sender, RoutedEventArgs e) { // 显示加载覆盖层 LoadingOverlay.Visibility = Visibility.Visible; try { // 启动新窗口的核心逻辑 var newAppView = CoreApplication.CreateNewView(); int newViewId = 0; await newAppView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { Frame frame = new Frame(); frame.Navigate(typeof(YourNewWindowPage)); Window.Current.Content = frame; Window.Current.Activate(); newViewId = ApplicationView.GetForCurrentView().Id; }); // 切换到新窗口 bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId); } finally { // 无论结果如何,隐藏加载覆盖层 LoadingOverlay.Visibility = Visibility.Collapsed; } }
方案二:自定义进度环光标(进阶,真正替换系统光标)
如果你确实需要把光标本身换成进度环样式,就得用自定义光标。不过这个方法相对繁琐,需要准备动画光标文件:
步骤1:生成动画光标文件
UWP支持.ani格式的动画光标,你需要先把Progress Ring的动画帧导出成图片序列,再用工具(比如AniCursor)转换成.ani文件,然后把这个文件放到你的应用Assets文件夹里。
步骤2:在Package.appxmanifest中注册自定义光标
添加如下扩展声明,把光标文件和ID绑定:
<Package ...> <Applications> <Application ...> <!-- 原有内容 --> <Extensions> <uap:Extension Category="windows.customCursor"> <uap:CustomCursor> <uap:Cursor Id="1" Path="Assets/ProgressRing.ani"/> </uap:CustomCursor> </uap:Extension> </Extensions> </Application> </Applications> </Package>
步骤3:在代码中切换光标
在启动新窗口前后切换光标样式:
private async void OpenNewWindowButton_Click(object sender, RoutedEventArgs e) { // 保存原有光标,方便后续恢复 var originalCursor = Window.Current.CoreWindow.PointerCursor; // 设置自定义进度环光标 var loadingCursor = new CoreCursor(CoreCursorType.Custom, 1); Window.Current.CoreWindow.PointerCursor = loadingCursor; try { // 启动新窗口的逻辑(和方案一一致) var newAppView = CoreApplication.CreateNewView(); int newViewId = 0; await newAppView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { Frame frame = new Frame(); frame.Navigate(typeof(YourNewWindowPage)); Window.Current.Content = frame; Window.Current.Activate(); newViewId = ApplicationView.GetForCurrentView().Id; }); await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId); } finally { // 恢复原有光标 Window.Current.CoreWindow.PointerCursor = originalCursor; } }
方案对比
- 方案一实现简单,用户体验清晰,还能防止误操作,适合大多数场景;
- 方案二更贴近"替换光标"的需求,但需要额外处理光标文件,而且部分UWP控件可能会自行覆盖光标样式,导致效果不一致。
内容的提问来源于stack exchange,提问作者kdun0508
相关产品推荐
相关产品推荐

