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

.NET MAUI删除附件后ObservableCollection未实时更新问题求助

解决.NET MAUI中删除附件后即时更新风险档案视图的问题

问题根源

你在AddAttachmentModal中删除附件时,仅更新了数据库和Modal自身的Attachments集合,但打开的CreateAndUpdateRiskProfileView对应的ViewModel没有收到附件被删除的通知,其内存中的Attachments ObservableCollection并未同步移除该附件,因此视图不会自动刷新,直到重启应用重新加载数据。

解决方案:使用MVVM Toolkit的Messenger实现跨ViewModel通信

利用CommunityToolkit.Mvvm中的IMessenger可以轻松实现ViewModel之间的消息传递,在附件被删除时通知风险档案ViewModel更新集合。

步骤1:定义删除附件的消息类

在项目中添加一个消息类,用于传递被删除的附件对象:

using CommunityToolkit.Mvvm.Messaging.Messages;
using SiRiAs.Lib.Models;

namespace SiRiAs.Lib.Messages
{
    public class AttachmentDeletedMessage : ValueChangedMessage<Attachment>
    {
        public AttachmentDeletedMessage(Attachment value) : base(value)
        {
        }
    }
}

步骤2:在CreateAndUpdateRiskProfileViewModel中注册消息监听

修改CreateAndUpdateRiskProfileViewModel,注入IMessenger并注册消息处理:

using CommunityToolkit.Mvvm.Messaging;
// ... 其他using

[QueryProperty(nameof(Intent), nameof(Intent))]
[QueryProperty(nameof(Model), nameof(Model))]
[QueryProperty(nameof(ActivityId), nameof(ActivityId))]
public partial class CreateAndUpdateRiskProfileViewModel : ObservableObject, IRecipient<AttachmentDeletedMessage>
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IPopupProvider _popupProvider;
    private readonly IMessenger _messenger;

    // ... 现有代码

    public CreateAndUpdateRiskProfileViewModel(IUnitOfWork unitOfWork, IPopupProvider popupProvider, IMessenger messenger)
    {
        _unitOfWork = unitOfWork;
        _popupProvider = popupProvider;
        _messenger = messenger;
        _messenger.Register(this); // 注册消息监听
        PopulateRiskCategories();
    }

    // 实现消息处理方法
    public void Receive(AttachmentDeletedMessage message)
    {
        var deletedAttachment = message.Value;
        // 检查并移除集合中的对应附件
        var existingAttachment = Attachments.FirstOrDefault(a => a.Id == deletedAttachment.Id);
        if (existingAttachment != null)
        {
            Attachments.Remove(existingAttachment);
            isModelDirty = true;
            // 同步更新Model中的附件列表
            Model.Attachments.Remove(existingAttachment);
        }
    }

    // 视图销毁时注销监听,避免内存泄漏
    public void Cleanup()
    {
        _messenger.UnregisterAll(this);
    }
}

步骤3:在CreateAndUpdateRiskProfileView中添加清理逻辑

在视图的OnDisappearing方法中调用ViewModel的清理方法:

protected override void OnDisappearing()
{
    base.OnDisappearing();
    _viewModel.Cleanup();
}

步骤4:在AddAttachmentModalViewModel中发送删除消息

修改AddAttachmentModalViewModel的ShowDeleteOption方法,删除附件后发送消息:

using CommunityToolkit.Mvvm.Messaging;
// ... 其他using

public partial class AddAttachmentModalViewModel : ObservableObject
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IPopupProvider _popupProvider;
    private readonly IMessenger _messenger;

    // ... 现有代码

    public AddAttachmentModalViewModel(IUnitOfWork unitOfWork, IPopupProvider popupProvider, IAudioRecorder audioRecorder, IMessenger messenger)
    {
        _unitOfWork = unitOfWork;
        _popupProvider = popupProvider;
        _audioRecorder = audioRecorder;
        _messenger = messenger;
        OnSelectedAttachmentTypeChanged(SelectedAttachmentType);
    }

    [RelayCommand]
    public async void ShowDeleteOption(Attachment attachment)
    {
        var result = await _popupProvider.ShowDeleteAttachmentPopup();
        if(result.Equals(DeleteDialogResult.Delete))
        {
            var deleteResult = await _popupProvider.ShowDeletePopup();
            if(deleteResult.Equals(DeleteDialogResult.Delete))
            {
                _unitOfWork.Attachments.Remove(attachment); 
                await _unitOfWork.Save();
                Attachments.Remove(attachment);
                
                // 发送附件删除消息
                _messenger.Send(new AttachmentDeletedMessage(attachment));
                
                foreach(RiskProfile riskProfile in await _unitOfWork.RiskProfiles.GetAll())
                {
                    if(riskProfile.Attachments.Contains(attachment))
                    {
                        riskProfile.Attachments.Remove(attachment);
                    }
                }
                // 保存风险档案的更新
                await _unitOfWork.Save();
            }
        }
    }
}

其他可选方案:关闭Modal时刷新附件列表

如果不想用消息传递,也可以在关闭AddAttachmentModal后重新加载附件列表,适合小型应用:

[RelayCommand]
public async void AddAttachment()
{
    var selectedAttachment = await _popupProvider.ShowAddAttachmentPopup();
    if (selectedAttachment is not null && !AttachmentAlreadyAttached(selectedAttachment))
    {
        Attachments.Add(selectedAttachment);
        isModelDirty = true;
    }
    // 刷新附件列表,同步删除的内容
    RefreshAttachments();
}

private async void RefreshAttachments()
{
    // 从数据库重新加载当前风险档案的附件
    var freshProfile = await _unitOfWork.RiskProfiles.GetById(Model.Id);
    if (freshProfile != null)
    {
        Attachments = new ObservableCollection<Attachment>(freshProfile.Attachments);
    }
}

内容的提问来源于stack exchange,提问作者Leah Fernández

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 14:40:20