feat: sichtbare Seite nach eingehendem Sync automatisch neu laden
EventApplier schreibt eingehende Sync-Ereignisse absichtlich direkt auf die rohe LiteDB-Collection (Ping-Pong-Vermeidung), benachrichtigt dabei aber kein ViewModel - eine per Sync empfangene neue Stunde erschien bisher erst nach manuellem Neuladen (z.B. Tab-Wechsel). Neues SyncEngine.DataChanged-Ereignis, gefeuert nach jedem Pull mit Ereignissen sowie bei einer RemoteWon-Konfliktauflösung; SyncStatusViewModel reicht es durch. MainWindowViewModel abonniert es und lädt ausschließlich die gerade sichtbare Seite über ihren eigenen, längst vorhandenen Lade-Einstieg neu - keine Navigation weg von offenen Detailansichten, keine neue Lade-Logik, und eine laufende Inline-Bearbeitung (Schülerdetail) wird nicht überschrieben. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using LehrerApp.Core.Services;
|
||||
@@ -43,6 +44,39 @@ public partial class MainWindowViewModel : ObservableObject
|
||||
CurrentSchoolYear = sy.CurrentSchoolYear();
|
||||
CurrentPage = dashboard;
|
||||
AppLock.ApplyConfig();
|
||||
SyncStatus.DataChanged += OnSyncDataChanged;
|
||||
}
|
||||
|
||||
// EventApplier schreibt bei eingehenden Sync-Ereignissen absichtlich direkt auf die rohe
|
||||
// LiteDB-Collection, an jedem ViewModel vorbei (Ping-Pong-Vermeidung, siehe EventApplier-
|
||||
// Klassenkommentar) - ohne diesen Hook blieb die gerade sichtbare Seite bis zum nächsten
|
||||
// manuellen Neuladen (z.B. Tab-Wechsel) auf dem alten Stand (TODO 10.1.11). Lädt bewusst nur
|
||||
// die aktuell sichtbare Seite über ihren eigenen, längst vorhandenen Lade-Einstieg neu - keine
|
||||
// neue Lade-Logik, keine Navigation weg von einer offenen Detailansicht. SyncEngine.DataChanged
|
||||
// feuert aus dem Sync-Timer-Hintergrundthread - daher der Dispatcher-Sprung zurück auf den
|
||||
// UI-Thread (gleiches Muster wie NotificationService.Show).
|
||||
private void OnSyncDataChanged()
|
||||
{
|
||||
if (Dispatcher.UIThread.CheckAccess()) RefreshCurrentPage();
|
||||
else Dispatcher.UIThread.Post(RefreshCurrentPage);
|
||||
}
|
||||
|
||||
private void RefreshCurrentPage()
|
||||
{
|
||||
switch (CurrentPage)
|
||||
{
|
||||
case DashboardViewModel vm: vm.RefreshCommand.Execute(null); break;
|
||||
case GroupListViewModel vm: vm.RefreshCommand.Execute(null); break;
|
||||
case StudentListViewModel vm: vm.LoadStudents(); break;
|
||||
case TimetableViewModel vm: vm.Load(); break;
|
||||
case WorkloadViewModel vm:
|
||||
vm.Tasks.Load(); vm.TimeTracking.Load(); vm.Evaluation.Load(); break;
|
||||
case GroupDetailViewModel { Group: { } group } vm: vm.LoadGroup(group.Id); break;
|
||||
// Inline-Bearbeitung (IsEditing) nicht überschreiben - anders als die Gruppenansicht
|
||||
// laufen Namens-/Geschlechtsänderungen hier nicht über einen Dialog.
|
||||
case StudentDetailViewModel { Student: { } student, IsEditing: false } vm:
|
||||
vm.LoadStudent(student.Id); break;
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnActiveNavItemChanged(NavItem value)
|
||||
|
||||
@@ -15,6 +15,12 @@ public partial class SyncStatusViewModel : ObservableObject
|
||||
[ObservableProperty] private bool _isServerConfigured;
|
||||
[ObservableProperty] private int _pendingCount;
|
||||
|
||||
/// <summary>Feuert, wenn ein Sync tatsächlich Daten angewendet hat (siehe SyncEngine.
|
||||
/// DataChanged, TODO 10.1.11) - MainWindowViewModel nutzt das, um die gerade sichtbare Seite
|
||||
/// neu zu laden, da EventApplier absichtlich an jedem ViewModel vorbei direkt auf die LiteDB
|
||||
/// schreibt.</summary>
|
||||
public event Action? DataChanged;
|
||||
|
||||
public SyncStatusViewModel(SyncEngine? engine)
|
||||
{
|
||||
_engine = engine;
|
||||
@@ -22,6 +28,7 @@ public partial class SyncStatusViewModel : ObservableObject
|
||||
if (_engine is not null)
|
||||
{
|
||||
_engine.StatusChanged += OnStatus;
|
||||
_engine.DataChanged += () => DataChanged?.Invoke();
|
||||
// SyncEngine feuert sein erstes StatusChanged bereits im eigenen Konstruktor
|
||||
// (UpdateStatus) - der läuft aber schon, während wir hier noch in GetService<SyncEngine>()
|
||||
// stecken, also VOR dem obigen Abonnieren. Ohne diesen Nachhol-Aufruf bliebe StatusText
|
||||
|
||||
Reference in New Issue
Block a user