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

WinUI3中CommunityToolkit.MVVM WeakReferenceMessenger调用已释放对象问题

解决WinUI3中WeakReferenceMessenger引发的ObjectDisposedException问题

你遇到的问题核心在于:WeakReferenceMessenger仅通过弱引用避免订阅者被Messenger强引用导致内存泄漏,但当订阅者(UserControl)已被Disposed但尚未被GC回收时,Messenger仍能通过弱引用获取到实例并调用Receive方法,进而触发已释放对象的访问异常。以下是几种可行的解决方法:

方法1:在UserControl的Dispose阶段主动取消订阅

WinUI3的UserControl实现了IDisposable接口,可通过重写Dispose方法在对象释放时直接取消消息订阅,从根源上避免后续消息触发Receive逻辑。

示例代码:

public partial class YourUserControl : UserControl
{
    private bool _isDisposed;

    protected override void Dispose(bool disposing)
    {
        if (!_isDisposed)
        {
            if (disposing)
            {
                // 取消对应消息类型的订阅,若使用了token需一并传入
                WeakReferenceMessenger.Default.Unregister<YourMessageType>(this);
                // 若订阅了多种消息,需分别取消
                // WeakReferenceMessenger.Default.Unregister<AnotherMessageType>(this);
            }

            _isDisposed = true;
            base.Dispose(disposing);
        }
    }

    // 你的消息接收方法
    public void Receive(YourMessageType message)
    {
        // 业务逻辑
    }
}

方法2:在Receive方法中先检查对象释放状态

如果无法在Dispose阶段及时取消订阅(比如存在复杂的生命周期依赖),可在Receive方法开头先判断对象是否已释放,避免访问已释放的资源。

示例代码:

public partial class YourUserControl : UserControl
{
    private bool _isDisposed;

    protected override void Dispose(bool disposing)
    {
        if (!_isDisposed)
        {
            if (disposing)
            {
                // 其他释放逻辑
            }

            _isDisposed = true;
            base.Dispose(disposing);
        }
    }

    public void Receive(YourMessageType message)
    {
        // 先判断对象是否已释放,若已释放直接返回
        if (_isDisposed || !this.IsLoaded)
        {
            return;
        }

        // 原业务逻辑,确保只在对象有效时执行
        // ...
    }
}

方法3:利用控件Unloaded事件辅助取消订阅

结合WinUI控件的Unloaded事件,在控件从视觉树移除时取消订阅,能更精准地匹配控件的可用生命周期:

public YourUserControl()
{
    InitializeComponent();
    WeakReferenceMessenger.Default.Register<YourMessageType>(this, Receive);
    this.Unloaded += (s, e) => WeakReferenceMessenger.Default.Unregister<YourMessageType>(this);
}

关键注意事项

  • WeakReferenceMessenger的弱引用仅负责避免内存泄漏,不处理对象已Disposed但未被GC回收的场景,这是设计预期,并非bug。
  • 若使用了自定义的订阅token,取消订阅时必须传入相同的token,否则无法正确取消。
  • 对于WinUI3控件,优先在Dispose或Unloaded事件中处理订阅取消,这两个时机能更精准地把控控件的生命周期边界。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:37:18