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

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.

崩溃原因分析

  1. 错误依赖UWP窗口API:WinUI3已不再推荐使用Window.Current和SystemNavigationManager.GetForCurrentView()这类UWP API,单例初始化时Window.Current可能尚未指向有效窗口实例,导致访问无效内存。
  2. 控件树循环引用风险:将UserControl自身设置为Popup的Child,初始化阶段易造成控件树循环引用,触发内存访问保护机制。
  3. 事件订阅时机错误:在构造函数中提前订阅窗口事件,此时窗口上下文未完全初始化,引发内存异常。

修复方案及代码调整

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 20:50:31