Optimierung des Startvorgangs, lazy load, async im thread pool oder während des Startbildschirms vor dem Mainwindow.
CI / build-and-test (push) Canceled after 0s

This commit is contained in:
2026-09-02 21:46:01 +02:00
parent 94946ffefb
commit 7ef0c95a73
4 changed files with 20 additions and 19 deletions
+14 -12
View File
@@ -52,7 +52,7 @@ public class App : Application
base.OnFrameworkInitializationCompleted();
}
private static void ContinueStartup(
private static async void ContinueStartup(
IClassicDesktopStyleApplicationLifetime desktop, SplashWindow splash)
{
// Verschlüsselte Datenbank (13.3.4): Passwort abfragen, bevor die Datenbank
@@ -62,11 +62,10 @@ public class App : Application
var promptVm = new DbPasswordPromptViewModel(
new DatabaseEncryptionService(), AppBootstrapper.ResolveDbPath());
var promptWindow = new DbPasswordPromptWindow { DataContext = promptVm };
promptVm.OnUnlocked = password =>
promptVm.OnUnlocked = async password =>
{
AppBootstrapper.DbPassword = password;
StartMainApp(desktop, splash);
promptWindow.Close();
await StartMainAppAsync(desktop, promptWindow);
};
desktop.MainWindow = promptWindow;
promptWindow.Show();
@@ -74,10 +73,10 @@ public class App : Application
return;
}
StartMainApp(desktop, splash);
await StartMainAppAsync(desktop, splash);
}
private static void StartMainApp(
private static async Task StartMainAppAsync(
IClassicDesktopStyleApplicationLifetime desktop, Window? windowToClose = null)
{
_serviceProvider = AppBootstrapper.BuildServices();
@@ -98,13 +97,16 @@ public class App : Application
var mainVm = Services.GetRequiredService<MainWindowViewModel>();
WireCallbacks(mainVm);
// DI-Singletons werden erst beim ersten Auflösen erzeugt. Ohne dieses explizite
// Auflösen entstand der Timer des optionalen WebUntis-Abgleichs erst, wenn die
// Einstellungen geöffnet oder ein manueller Abruf gestartet wurde. Den Dienst beim
// Anwendungsstart aktivieren und wie den Jahresplan sofort einmal abgleichen; danach
// übernimmt sein stündlicher Timer.
// Beide optionalen Erstabgleiche noch unter dem Splashscreen abschließen. Ihre
// CPU-/Datenbankarbeit läuft innerhalb der Dienste im Threadpool; dadurch öffnet das
// Hauptfenster mit fertigem Datenstand und friert nicht kurz danach ein. Das Auflösen
// aktiviert zugleich die periodischen Timer.
var initialPolls = new List<Task>();
if (Services.GetService<UntisSyncService>() is { } untisSync)
_ = untisSync.PollAsync();
initialPolls.Add(untisSync.PollAsync());
if (Services.GetService<AnnualPlanSyncService>() is { } annualPlanSync)
initialPolls.Add(annualPlanSync.PollAsync());
await Task.WhenAll(initialPolls);
var main = new MainWindow { DataContext = mainVm };
main.EnableWindowSizePersistence(Services.GetRequiredService<WindowSettingsService>());
@@ -38,7 +38,7 @@ public sealed class AnnualPlanSyncService : IDisposable
public async Task PollAsync()
{
if (!await _gate.WaitAsync(0)) return;
if (!await _gate.WaitAsync(0).ConfigureAwait(false)) return;
try
{
var url = _settings.GetIcalUrl();
@@ -47,7 +47,7 @@ public sealed class AnnualPlanSyncService : IDisposable
string icsText;
try
{
icsText = await _http.GetStringAsync(url);
icsText = await _http.GetStringAsync(url).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -59,7 +59,7 @@ public sealed class AnnualPlanSyncService : IDisposable
AnnualPlanPollResult result;
try
{
result = ProcessIcsText(icsText);
result = await Task.Run(() => ProcessIcsText(icsText)).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -67,7 +67,7 @@ public class UntisSyncService : IDisposable
public async Task PollAsync()
{
if (!await _gate.WaitAsync(0)) return;
if (!await _gate.WaitAsync(0).ConfigureAwait(false)) return;
try
{
var url = _settings.GetIcalUrl();
@@ -76,7 +76,7 @@ public class UntisSyncService : IDisposable
string icsText;
try
{
icsText = await _http.GetStringAsync(url);
icsText = await _http.GetStringAsync(url).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -88,7 +88,7 @@ public class UntisSyncService : IDisposable
UntisPollResult result;
try
{
result = ProcessIcsText(icsText);
result = await Task.Run(() => ProcessIcsText(icsText)).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -170,7 +170,6 @@ public partial class DashboardViewModel : ObservableObject
if (annualPlanSync is not null)
{
annualPlanSync.DataChanged += () => Avalonia.Threading.Dispatcher.UIThread.Post(LoadCalendar);
_ = annualPlanSync.PollAsync();
}
LoadDashboardCards();
Load();