.NET MAUI ObjectDisposedException异常求助:无法访问已释放对象
.NET MAUI应用崩溃:System.ObjectDisposedException异常
我的.NET MAUI应用崩溃,抛出异常:
System.ObjectDisposedException: 'Cannot access a disposed object. Object name: 'Microsoft.Maui.Platform.LayoutViewGroup'.'
我使用WeakReferenceMessenger实现视图刷新,自定义了RefreshManager类:
using CommunityToolkit.Mvvm.Messaging; namespace NuesWarehouseMobile.Utilities { internal static class RefreshManager { public static void RequestRefresh(string viewName) { WeakReferenceMessenger.Default.Send(new RefreshViewMessage(viewName)); } public static void Register<TRecipient>(TRecipient recipient, Action<RefreshViewMessage> action) where TRecipient : class { WeakReferenceMessenger.Default.Register<RefreshViewMessage>(recipient, (r, m) => action(m)); } public static void Unregister<TRecipient>(TRecipient recipient) where TRecipient : class { WeakReferenceMessenger.Default.Unregister<RefreshViewMessage>(recipient); } } public class RefreshViewMessage { public string ViewName { get; } public RefreshViewMessage(string viewName) { ViewName = viewName; } } }
但弱引用机制触发了上述异常。尝试过缓存视图避免被释放、使用强引用等方法均未解决;其他视图更新方式无效,必须依赖消息机制。
以下是DocumentiDaEvadereView的视图逻辑代码:
using CommunityToolkit.Mvvm.Messaging; using NuesWarehouse.Core.Dtos; using NuesWarehouseMobile.Core.Interfaces.Services; using NuesWarehouseMobile.Utilities; using System.Collections.ObjectModel; using System.Diagnostics; using System.Windows.Input; namespace NuesWarehouseMobile.MenuView; public partial class DocumentiDaEvadereView : ContentView { private readonly IDocumentService _documentService; private int currentPage = 1; private int perPage = 20; private string stato = "Aperto-Picking-Parzialmente Evaso"; //SPAZIO VUOTO private string tipoDoc = "OrdineVendita"; private bool _isLoading; public bool IsLoading { get => _isLoading; set { _isLoading = value; OnPropertyChanged(nameof(IsLoading)); } } public ObservableCollection<DocumentiDto> Documents { get; set; } public ICommand LoadDocumentsCommand { get; } public ICommand NextPageCommand { get; } public ICommand PreviousPageCommand { get; } private int _currentPageDisplay; public int CurrentPageDisplay { get => _currentPageDisplay; set { _currentPageDisplay = value; OnPropertyChanged(); } } public DocumentiDaEvadereView() { InitializeComponent(); RefreshManager.Register(this, OnRefreshViewMessageReceived); IsLoading = true; _documentService = Application.Current.Handler.MauiContext.Services.GetService<IDocumentService>(); Documents = new ObservableCollection<DocumentiDto>(); LoadDocumentsAsync(); LoadDocumentsCommand = new Command(async () => await LoadDocumentsAsync()); NextPageCommand = new Command(async () => await LoadNextPageAsync()); PreviousPageCommand = new Command(async () => await LoadPreviousPageAsync()); double screenHeight = DeviceDisplay.MainDisplayInfo.Height / DeviceDisplay.MainDisplayInfo.Density; double gridHeight = screenHeight * 0.6; DocumentsDataGrid.HeightRequest = gridHeight; BindingContext = this; LoadDocumentsCommand.Execute(null); IsLoading = false; } private async Task LoadDocumentsAsync(int page = 1) { var documents = await _documentService.GetDocumentsByPage(page, perPage, tipoDoc, stato); Documents.Clear(); foreach (var document in documents) { if (document.Stato == "Evaso") { document.StatoColor = "Green"; } else if (document.Stato == "Parzialmente Evaso") { document.StatoColor = "Orange"; } else { document.StatoColor = "Yellow"; } Documents.Add(document); } CurrentPageDisplay = currentPage; DocumentsDataGrid.ItemsSource = null; DocumentsDataGrid.ItemsSource = Documents; } private async Task LoadNextPageAsync() { currentPage++; await LoadDocumentsAsync(currentPage); } private async Task LoadPreviousPageAsync() { if (currentPage > 1) { currentPage--; await LoadDocumentsAsync(currentPage); } } // 打开新视图的方法 private void ApriNuovaPaginaCommand(object sender, EventArgs e) { IsLoading = true; var button = sender as Button; if (button?.CommandParameter is string documentId) { Debug.WriteLine(documentId); Navigation.PushAsync(new EvasioneDocumentoPage(documentId)); } else { Debug.WriteLine("====ATTENZIONE, PARAMETRO documentId NON PASSATO CORRETTAMENTE===="); } IsLoading = false; } private void OnRefreshViewMessageReceived(RefreshViewMessage message) { if (message.ViewName == "EvasioneDocumento") // 参数检查 { Debug.WriteLine("Messaggio ricevuto in DocumentsView! Aggiorno i documenti..."); _ = LoadDocumentsAsync(1); // 重新加载文档 } } ~DocumentiDaEvadereView() { // 注销以避免内存泄漏 RefreshManager.Unregister(this); } }
解决方案
问题根源
- 析构函数不可靠:析构函数由GC在不确定时机调用,此时视图可能已被释放,WeakReferenceMessenger仍可能在视图处置后触发回调,导致访问已释放的
LayoutViewGroup。 - 未检查视图状态:消息回调中直接执行UI更新,未验证视图是否处于可用(未处置)状态。
修复步骤
1. 用生命周期方法替换析构函数
对于ContentView,重写OnParentRemoved方法,确保视图被移除时立即注销消息订阅:
protected override void OnParentRemoved() { base.OnParentRemoved(); RefreshManager.Unregister(this); }
如果该视图是导航页面的一部分,可结合OnDisappearing做更精准的注销:
protected override void OnDisappearing() { base.OnDisappearing(); if (!Navigation.NavigationStack.Contains(this)) { RefreshManager.Unregister(this); } }
2. 消息回调中检查视图状态
在接收消息时,先验证视图未被处置,再执行UI更新:
private void OnRefreshViewMessageReceived(RefreshViewMessage message) { if (message.ViewName == "EvasioneDocumento" && !IsDisposed) { Debug.WriteLine("Messaggio ricevuto in DocumentsView! Aggiorno i documenti..."); // 确保在主线程执行UI更新 MainThread.BeginInvokeOnMainThread(async () => await LoadDocumentsAsync(1)); } }
3. 确保UI操作在主线程执行
优化LoadDocumentsAsync,将所有UI更新逻辑包裹在主线程调用中:
private async Task LoadDocumentsAsync(int page = 1) { IsLoading = true; var documents = await _documentService.GetDocumentsByPage(page, perPage, tipoDoc, stato); await MainThread.InvokeOnMainThreadAsync(() => { Documents.Clear(); foreach (var document in documents) { document.StatoColor = document.Stato switch { "Evaso" => "Green", "Parzialmente Evaso" => "Orange", _ => "Yellow" }; Documents.Add(document); } CurrentPageDisplay = currentPage; DocumentsDataGrid.ItemsSource = Documents; }); IsLoading = false; }
额外建议
避免在构造函数中直接调用异步方法,将初始化逻辑移至OnAppearing:
protected override async void OnAppearing() { base.OnAppearing(); if (Documents.Count == 0) { await LoadDocumentsAsync(); } }
内容的提问来源于stack exchange,提问作者Matteo Lanza
相关产品推荐
相关产品推荐

