I am working on an App, in which I am able to attach attachments like images and audio to a profile and display those attachments in CreateAndUpdateRiskProfileView
. I can add attachments with the AddAttachmentModal
. When I choose an attachment there it will be automatically displayed in the CreateAndUpdatetRiskProfileView
. Now I also want to be able to delete attachments permanently from the database. This is possible when I longpress on an attachment in the AddAttachmentModal
and select delete
. Now this works and the attachment is not being displayed in the AddAttachmentModal
and if I go to another profile which used this attachment, the attachment is also gone. However, in the CreateAndUpdateRiskProfileView
of the Profile where I just deleted an attachment this attachment is still there and will remain there until I close the App and build again.
I want the deleted attachment to not show anymore imidiatly, but I don't know how I can make this happen.
I would appreciate the help!
This is the CreateAndUpdateRiskProfileView
:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:SiRiAs.Controls"
xmlns:flowlayout="clr-namespace:SiRiAs.Controls.FlowLayout"
xmlns:behaviours="clr-namespace:SiRiAs.Behaviors"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:convertes="clr-namespace:SiRiAs.Lib.Converters;assembly=SiRiAs.Lib"
xmlns:selectors="clr-namespace:SiRiAs.Lib.TemplateSelectors;assembly=SiRiAs.Lib"
xmlns:viewmodel="clr-namespace:SiRiAs.Lib.ViewModels;assembly=SiRiAs.Lib"
xmlns:models="clr-namespace:SiRiAs.Lib.Models;assembly=SiRiAs.Lib"
x:Class="SiRiAs.Views.CreateAndUpdateRiskProfileView"
x:DataType="viewmodel:CreateAndUpdateRiskProfileViewModel"
Shell.NavBarIsVisible="False">
<ContentPage.Resources>
<ResourceDictionary>
<convertes:LocationToStringConverter x:Key="LocationToStringConverter"
DefaultConvertReturnValue="0°0'0''N 0°0'0''W"/>
<DataTemplate x:Key="ImageAttachmentView"
x:DataType="models:Attachment">
<controls:LongPressImageButton Style="{StaticResource PreviewImageButtonStyle}"
Aspect="AspectFill"
HeightRequest="70"
WidthRequest="70"
Source="{Binding Link}"
LongPressCommand="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:CreateAndUpdateRiskProfileViewModel}}, Path=ShowDeleteOptionCommand}"
LongPressCommandParameter="{Binding .}"
/>
</DataTemplate>
<DataTemplate x:Key="AudioAttachmentView"
x:DataType="models:Attachment">
<controls:LongPressButton Style="{StaticResource PreviewButtonStyle}"
Text="{Binding Name}"
HeightRequest="70"
WidthRequest="70"
LongPressCommand="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:CreateAndUpdateRiskProfileViewModel}}, Path=ShowDeleteOptionCommand}"
LongPressCommandParameter="{Binding .}"/>
</DataTemplate>
This is the CreateAndUpdateProfileView.xaml.cs
using SiRiAs.Lib.ViewModels;
namespace SiRiAs.Views;
public partial class CreateAndUpdateRiskProfileView : ContentPage {
private readonly CreateAndUpdateRiskProfileViewModel _viewModel;
public CreateAndUpdateRiskProfileView(CreateAndUpdateRiskProfileViewModel createAndUpdateRiskProfileViewModel) {
InitializeComponent();
_viewModel = createAndUpdateRiskProfileViewModel;
BindingContext = createAndUpdateRiskProfileViewModel;
}
protected override bool OnBackButtonPressed() {
if(_viewModel.ReturnOrPopupCommand.CanExecute(null)) {
_viewModel.ReturnOrPopupCommand.Execute(null);
}
return true;
}
}
This is the CreateAndUpdateRiskProfileViewModel
:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using SiRiAs.Lib.Helpers;
using SiRiAs.Lib.Models;
using SiRiAs.Lib.Repositories;
using SiRiAs.Lib.Services;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace SiRiAs.Lib.ViewModels {
[QueryProperty(nameof(Intent), nameof(Intent))]
[QueryProperty(nameof(Model), nameof(Model))]
[QueryProperty(nameof(ActivityId), nameof(ActivityId))]
public partial class CreateAndUpdateRiskProfileViewModel : ObservableObject {
private readonly IUnitOfWork _unitOfWork;
private readonly IPopupProvider _popupProvider;
private bool isModelDirty;
public Guid ActivityId { get; set; }
[ObservableProperty]
private Intent intent = Intent.Create;
[ObservableProperty]
private RiskProfile model = new();
[ObservableProperty]
private ObservableCollection<Attachment> attachments = new();
//...
public CreateAndUpdateRiskProfileViewModel(IUnitOfWork unitOfWork, IPopupProvider popupProvider) {
_unitOfWork = unitOfWork;
_popupProvider = popupProvider;
PopulateRiskCategories();
}
/// <summary>
/// Populate fields if model is loaded from database
/// </summary>
/// <param name="value">model</param>
partial void OnModelChanged(RiskProfile value) {
if (value is not null) {
CreationTimeStamp = Model.CreationDate;
SelectedRiskCategory = AvailableRiskCategories.FirstOrDefault(riskCategory => riskCategory.Id == Model.RiskCategory?.Id);
SelectedRiskFeature = AvailableRiskFeatures.FirstOrDefault(riskFeature => riskFeature.Id == Model.RiskFeature?.Id);
DangerLevel = Model.DangerLevel;
Description = Model.Description;
Measures = Model.Measures;
Location = Model.Location;
Attachments = new ObservableCollection<Attachment>(model.Attachments);
isModelDirty = false;
}
}
/// <summary>
/// Add model to database
/// </summary>
[RelayCommand]
public async void CreateOrUpdate() {
CommitChanges();
if (Intent == Intent.Create) {
Model.ActivityId = ActivityId;
Model.CreationDate = Model.LastChangeDate = CreationTimeStamp;
await _unitOfWork.RiskProfiles.Add(Model);
await _unitOfWork.Save();
Model.Attachments = Attachments.ToList();
} else if (Intent == Intent.Update) {
Model.LastChangeDate = DateTime.Now;
Model.Attachments = Attachments.ToList();
_unitOfWork.RiskProfiles.Update(Model);
}
await _unitOfWork.Save();
NavigateBack();
}
[RelayCommand]
public async void AddAttachment() {
var selectedAttachment = await _popupProvider.ShowAddAttachmentPopup();
if (selectedAttachment is not null && !AttachmentAlreadyAttached(selectedAttachment)) {
Attachments.Add(selectedAttachment);
isModelDirty = true;
}
}
[RelayCommand]
public async void ShowDeleteOption(Attachment attachment) {
var result = await _popupProvider.ShowDeleteAttachmentModal();
if(result.Equals(MoreOptionsPopupResult.Delete)) {
var deleteResult = await _popupProvider.ShowDeletePopup();
if(deleteResult.Equals(DeleteDialogResult.Delete)) {
Attachments.Remove(attachment);
isModelDirty = true;
}
}
}
//...
This the the AddAttachmentModal
which gets via AddAttachment()
:
modals:BaseModalPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:modals="clr-namespace:SiRiAs.Views.Modals"
xmlns:controls="clr-namespace:SiRiAs.Controls"
xmlns:viewmodel="clr-namespace:SiRiAs.Lib.ViewModels;assembly=SiRiAs.Lib"
xmlns:behaviors="clr-namespace:SiRiAs.Behaviors"
xmlns:selectors="clr-namespace:SiRiAs.Lib.TemplateSelectors;assembly=SiRiAs.Lib"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:models="clr-namespace:SiRiAs.Lib.Models;assembly=SiRiAs.Lib"
x:Class="SiRiAs.Views.Modals.AddAttachmentModal"
x:DataType="viewmodel:AddAttachmentModalViewModel"
xmlns:convertes="clr-namespace:SiRiAs.Lib.Converters;assembly=SiRiAs.Lib"
Title="AddAttachmentPopup">
<ContentPage.Resources>
<DataTemplate x:Key="ImageAttachmentView" x:DataType="models:Attachment">
<controls:LongPressImageButton Style="{StaticResource PreviewImageButtonStyle}"
Aspect="AspectFill"
Source="{Binding Link}"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:AddAttachmentModalViewModel}}, Path=SelectedCommand}"
CommandParameter="{Binding .}"
LongPressCommand="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:AddAttachmentModalViewModel}}, Path=ShowDeleteOptionCommand}"
LongPressCommandParameter="{Binding .}"
/>
</DataTemplate>
<DataTemplate x:Key="AudioAttachmentView" x:DataType="models:Attachment">
<controls:LongPressButton Style="{StaticResource PreviewButtonStyle}"
Text="{Binding Name}"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:AddAttachmentModalViewModel}}, Path=SelectedCommand}"
CommandParameter="{Binding .}"
LongPressCommand="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:AddAttachmentModalViewModel}}, Path=ShowDeleteOptionCommand}"
LongPressCommandParameter="{Binding .}"
/>
</DataTemplate>
//...
The AddAttachmentModalViewModel
:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using SiRiAs.Lib.Models;
using SiRiAs.Lib.Repositories;
using System.Collections.ObjectModel;
using System.Diagnostics;
using SiRiAs.Lib.Services;
using SiRiAs.Lib.Helpers;
namespace SiRiAs.Lib.ViewModels {
public partial class AddAttachmentModalViewModel : ObservableObject {
[ObservableProperty]
private ObservableCollection<Attachment> attachments;
private readonly IUnitOfWork _unitOfWork;
private readonly IPopupProvider _popupProvider;
//...
public AddAttachmentModalViewModel(IUnitOfWork unitOfWork, IPopupProvider popupProvider, IAudioRecorder audioRecorder) {
_unitOfWork = unitOfWork;
_popupProvider = popupProvider;
_audioRecorder = audioRecorder;
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);
foreach(RiskProfile riskProfile in await _unitOfWork.RiskProfiles.GetAll()){
if(riskProfile.Attachments.Contains(attachment)) {
riskProfile.Attachments.Remove(attachment);
}
}
}
//...
}
}