WinUI 3中ProgressRing初始化时在Visual Studio 2022崩溃求助
WinUI3 ProgressRing控件初始化崩溃问题解决
问题场景
在WinUI3应用中实现点击按钮显示进度环的功能,使用单例模式封装ProgressRing控件,但控件初始化时触发崩溃,报错:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
崩溃原因分析
- 错误依赖UWP窗口API:WinUI3已不再推荐使用
Window.Current和SystemNavigationManager.GetForCurrentView()这类UWP API,单例初始化时Window.Current可能尚未指向有效窗口实例,导致访问无效内存。 - 控件树循环引用风险:将UserControl自身设置为Popup的Child,初始化阶段易造成控件树循环引用,触发内存访问保护机制。
- 事件订阅时机错误:在构造函数中提前订阅窗口事件,此时窗口上下文未完全初始化,引发内存异常。
修复方案及代码调整
1. 重构ProgressRingControl实现
移除对UWP窗口API的依赖,调整Popup逻辑,在显示时动态绑定窗口尺寸:
ProgressRingControl.xaml.cs 修改后代码
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls.Primitives; namespace progress_sample { public sealed partial class ProgressRingControl : UserControl { private Popup _popup; private static ProgressRingControl _instance; private ProgressRingControl() { this.InitializeComponent(); _popup = new Popup { Child = this }; } public static ProgressRingControl Instance { get { _instance ??= new ProgressRingControl(); return _instance; } } public void ShowProgressRing() { if (_popup.IsOpen) return; var currentWindow = App.Current.Windows[0] as Window; if (currentWindow == null) return; // 匹配窗口尺寸 this.Width = currentWindow.Bounds.Width; this.Height = currentWindow.Bounds.Height; // 订阅窗口尺寸变化 currentWindow.SizeChanged += CurrentWindow_SizeChanged; IndeterminateProgress.IsActive = true; _popup.IsOpen = true; } private void CurrentWindow_SizeChanged(object sender, WindowSizeChangedEventArgs args) { var window = sender as Window; if (window != null) { this.Width = window.Bounds.Width; this.Height = window.Bounds.Height; } } public void HideProgressRing() { if (!_popup.IsOpen) return; IndeterminateProgress.IsActive = false; _popup.IsOpen = false; // 取消事件订阅,避免内存泄漏 var currentWindow = App.Current.Windows[0] as Window; if (currentWindow != null) { currentWindow.SizeChanged -= CurrentWindow_SizeChanged; } } } }
2. 验证App.xaml.cs窗口初始化
确保App类中正确初始化并持有主窗口引用:
using Microsoft.UI.Xaml; namespace progress_sample { public partial class App : Application { public App() { this.InitializeComponent(); } protected override void OnLaunched(LaunchActivatedEventArgs args) { _mainWindow = new MainWindow(); _mainWindow.Activate(); } private Window _mainWindow; } }
3. 保留原有MainWindow逻辑
MainWindow的XAML和后台代码无需修改,点击按钮的逻辑保持原样即可。
关键修改点说明
- 移除
Window.Current和SystemNavigationManager相关代码,改用WinUI3原生的App.Current.Windows获取当前窗口。 - 将窗口相关操作延迟到
ShowProgressRing方法中,确保窗口上下文已完全初始化。 - 仅在显示进度环时订阅窗口尺寸变化事件,隐藏时取消订阅,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Sumnoon
相关产品推荐
相关产品推荐

