From e3942d00cc4f59c7e5f0225955fef46cb031f5c0 Mon Sep 17 00:00:00 2001 From: MarcoE Date: Wed, 16 Sep 2026 13:23:34 +0200 Subject: [PATCH] Fix rilevamento modifiche nella scheda: articoli e allegati Uscendo dalla scheda il prompt di salvataggio non compariva e il pulsante "Salva" restava nascosto, perche' IsDirty non vedeva il lavoro fatto: - gli articoli scelti dalla griglia (OpenSelectArt) non marcavano mai la scheda come modificata; - ValueComparer confronta solo i campi del form, quindi ogni RecalcDirty() successivo azzerava il flag alzato con forceTrue da scanner e allegati. Non bastava confrontare Articoli: Clone() e' un MemberwiseClone, quindi _originalScheda condivide la stessa lista. Ora il confronto usa uno snapshot dei barcode preso all'apertura piu' un flag per gli allegati (che vivono in AttachedList fino al salvataggio), e RecalcDirty() perde forceTrue: non puo' piu' essere azzerato. Le chiamate su insert/remove degli articoli erano anche fatte prima della modifica della lista, quindi valutavano lo stato precedente. Co-Authored-By: Claude Opus 5 (1M context) --- .../Modal/ModalFormScheda.razor | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor b/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor index 1d12fb1..f06ce21 100644 --- a/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor +++ b/SteUp.Shared/Components/SingleElements/Modal/ModalFormScheda.razor @@ -230,6 +230,11 @@ private int _noteFieldKey; private bool IsDirty { get; set; } private Scheda _originalScheda = null!; + // Clone() e' un MemberwiseClone, quindi _originalScheda condivide la stessa lista + // Articoli: per accorgerci degli articoli aggiunti/rimossi serve uno snapshot a parte. + private List _originalBarcodes = []; + // Gli allegati vivono in AttachedList finche' non si salva: li tracciamo con un flag. + private bool _attachmentsDirty; private List? AttachedList { get; set; } protected override void OnInitialized() @@ -240,6 +245,7 @@ OnScannerService.OnErrorScan += OnErrorScan; _originalScheda = Scheda.Clone(); + _originalBarcodes = Scheda.Articoli.ConvertAll(x => x.Barcode); Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopCenter; LoadAttached(); @@ -456,14 +462,29 @@ StateHasChanged(); } - private void RecalcDirty(bool forceTrue = false) + private void RecalcDirty() { - IsDirty = forceTrue || !ValueComparer.AreEqual(Scheda, _originalScheda); + IsDirty = _attachmentsDirty + || !ValueComparer.AreEqual(Scheda, _originalScheda) + || !BarcodesUnchanged(); if (IsDirty) LabelSave = !IsNew ? "Aggiorna" : "Salva"; else LabelSave = null; } + private bool BarcodesUnchanged() + { + if (Scheda.Articoli.Count != _originalBarcodes.Count) return false; + + for (var i = 0; i < _originalBarcodes.Count; i++) + { + if (!Scheda.Articoli[i].Barcode.Equals(_originalBarcodes[i], StringComparison.Ordinal)) + return false; + } + + return true; + } + private static class ValueComparer { public static bool AreEqual(Scheda? a, Scheda? b) @@ -526,7 +547,8 @@ await InvokeAsync(StateHasChanged); - RecalcDirty(true); + _attachmentsDirty = true; + RecalcDirty(); // Processa in background e aggiorna UI man mano (o a blocchi) _ = Task.Run(async () => @@ -618,7 +640,11 @@ }) ); - await InvokeAsync(StateHasChanged); + await InvokeAsync(() => + { + RecalcDirty(); + StateHasChanged(); + }); } }); } @@ -631,7 +657,8 @@ AttachedList[index].ToRemove = true; AttachedList.RemoveAt(index); - RecalcDirty(true); + _attachmentsDirty = true; + RecalcDirty(); StateHasChanged(); } @@ -701,14 +728,13 @@ if (art != null) { - RecalcDirty(true); - Scheda.Articoli.Insert(0, new SchedaArticolo { Barcode = art.Barcode, Descrizione = art.Descrizione }); + RecalcDirty(); StateHasChanged(); } else @@ -748,8 +774,8 @@ var index = Scheda.Articoli.FindIndex(x => x.Barcode.Equals(barcode)); if (index < 0) return; - RecalcDirty(true); Scheda.Articoli.RemoveAt(index); + RecalcDirty(); StateHasChanged(); }