284 lines
11 KiB
C#
284 lines
11 KiB
C#
using System;
|
|
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Project_Periodensystem.Model;
|
|
using Project_Periodensystem.Persistence;
|
|
using Project_Periodensystem.Controller;
|
|
|
|
namespace Project_Periodensystem.View
|
|
{
|
|
/// <summary>
|
|
/// Concrete Implementation des Navigation Service für Avalonia UI
|
|
///
|
|
/// ZWECK UND ARCHITEKTUR:
|
|
/// - Implementiert INavigationService Interface aus dem Controller-Layer
|
|
/// - Trennt sauber "WAS navigiert wird" (Controller) von "WIE navigiert wird" (View)
|
|
/// - Kapselt alle Avalonia-spezifische Navigation-Logik
|
|
/// - Ermöglicht verschiedene UI-Frameworks ohne Controller-Änderungen
|
|
///
|
|
/// DESIGN PATTERNS:
|
|
/// - Interface Implementation: Konkrete Umsetzung der abstrakten Navigation
|
|
/// - Dependency Injection: MainWindow wird von außen injiziert
|
|
/// - Facade Pattern: Vereinfacht komplexe UI-Navigation für Controller
|
|
/// - Bridge Pattern: Verbindet Controller (Abstraktion) mit View (Implementation)
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - Interface Implementation: public class NavigationService : INavigationService
|
|
/// - Constructor Injection: MainWindow als Dependency
|
|
/// - Null-Conditional Checks: Robuste Parameter-Validierung
|
|
/// - Exception Handling: Try-Catch für alle UI-Operationen
|
|
/// - Method Delegation: Weiterleitung von Interface-Aufrufen an UI-Code
|
|
///
|
|
/// AVALONIA-INTEGRATION:
|
|
/// - MainWindow.Content: Zentrale Inhaltsbereich für Page-Wechsel
|
|
/// - UserControl-basierte Pages: PeriodicTablePage, AboutPage, LandingPage
|
|
/// - Theme-Management: Avalonia Application Resources
|
|
/// - Application.Current: Globaler Zugriff auf App-Instance
|
|
///
|
|
/// ZIRKULÄRE ABHÄNGIGKEITEN:
|
|
/// - Problem: Controller braucht NavigationService, NavigationService braucht Controller
|
|
/// - Lösung: Zweistufige Initialisierung mit SetDataController()
|
|
/// - Constructor nimmt MainWindow, SetDataController() löst Zirkularität auf
|
|
/// </summary>
|
|
public class NavigationService : INavigationService
|
|
{
|
|
// ===== PRIVATE FELDER =====
|
|
|
|
/// <summary>
|
|
/// Referenz zum Hauptfenster der Avalonia-Anwendung
|
|
///
|
|
/// ZWECK:
|
|
/// - Zentrale Kontrolle über den Hauptinhaltsbereich
|
|
/// - Zugriff auf MainWindow.Content für Page-Wechsel
|
|
/// - Window-Eigenschaften (Titel, Größe, etc.) ändern
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - Readonly Field: Kann nur im Konstruktor gesetzt werden
|
|
/// - Reference Type: Hält Verweis auf MainWindow-Objekt
|
|
/// - Encapsulation: Private field mit controlled access
|
|
/// </summary>
|
|
private readonly MainWindow _mainWindow;
|
|
|
|
/// <summary>
|
|
/// Referenz zum Data Controller (für Daten-Zugriff)
|
|
///
|
|
/// ZWECK:
|
|
/// - Navigation-Pages benötigen Zugriff auf Element-Daten
|
|
/// - Vermeidung direkter Model/Persistence-Zugriffe aus View
|
|
/// - Konsistente Daten-API für alle UI-Komponenten
|
|
///
|
|
/// ZIRKULÄRE ABHÄNGIGKEIT:
|
|
/// - Controller erstellt NavigationService
|
|
/// - NavigationService braucht Controller für Daten
|
|
/// - Lösung: Nullable field + SetDataController() nach Konstruktion
|
|
/// </summary>
|
|
private PeriodensystemController? _dataController;
|
|
|
|
// ===== KONSTRUKTOR UND INITIALISIERUNG =====
|
|
|
|
/// <summary>
|
|
/// Konstruktor mit Dependency Injection des MainWindow
|
|
///
|
|
/// ZWECK:
|
|
/// - Initialisiert Navigation Service mit UI-Kontext
|
|
/// - Stellt sicher, dass MainWindow verfügbar ist
|
|
/// - Validiert kritische Dependencies
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - Constructor Dependency Injection: MainWindow als Parameter
|
|
/// - ArgumentNullException: Robuste Parameter-Validierung
|
|
/// - Null-Coalescing Throw: mainWindow ?? throw new ArgumentNullException()
|
|
/// - Self-Documenting Code: Logging der Initialisierung
|
|
///
|
|
/// PARAMETER-VALIDIERUNG:
|
|
/// - Null-Check mit Exception: Verhindert spätere NullReferenceExceptions
|
|
/// - Early Fail Principle: Probleme sofort erkennbar
|
|
/// - Descriptive Exception: nameof() für präzise Fehlermeldung
|
|
/// </summary>
|
|
/// <param name="mainWindow">Das Hauptfenster der Avalonia-Anwendung</param>
|
|
/// <exception cref="ArgumentNullException">Wenn mainWindow null ist</exception>
|
|
public NavigationService(MainWindow mainWindow)
|
|
{
|
|
_mainWindow = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow));
|
|
Logger.Log("NavigationService initialisiert - implementiert Interface-basierte Navigation");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setzt den Data Controller nach der Konstruktion (löst zirkuläre Abhängigkeit)
|
|
///
|
|
/// ZWECK:
|
|
/// - Zweistufige Initialisierung zur Auflösung zirkulärer Dependencies
|
|
/// - Ermöglicht Controller-Access für datenabhängige Navigation
|
|
/// - Trennt UI-Initialisierung von Daten-Initialisierung
|
|
///
|
|
/// ZIRKULÄRES ABHÄNGIGKEITS-PROBLEM:
|
|
/// 1. MainWindow erstellt PeriodensystemController
|
|
/// 2. Controller braucht NavigationService (this)
|
|
/// 3. NavigationService braucht Controller für Daten
|
|
/// 4. Lösung: Controller nach NavigationService-Konstruktion setzen
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - Two-Phase Construction: Konstruktor + Setter für komplexe Dependencies
|
|
/// - Null-Conditional Assignment: _dataController wird aus null zu gültigem Objekt
|
|
/// - Method Chaining möglich: SetDataController() könnte 'this' zurückgeben
|
|
/// </summary>
|
|
/// <param name="dataController">Der PeriodensystemController für Datenzugriff</param>
|
|
/// <exception cref="ArgumentNullException">Wenn dataController null ist</exception>
|
|
public void SetDataController(PeriodensystemController dataController)
|
|
{
|
|
_dataController = dataController ?? throw new ArgumentNullException(nameof(dataController));
|
|
Logger.Log("DataController in NavigationService gesetzt - zirkuläre Abhängigkeit aufgelöst");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Navigation zum Periodensystem (Interface Implementation)
|
|
/// </summary>
|
|
public void NavigateToPeriodicTable()
|
|
{
|
|
try
|
|
{
|
|
if (_dataController == null)
|
|
{
|
|
Logger.LogError("DataController nicht gesetzt");
|
|
return;
|
|
}
|
|
|
|
var periodicTablePage = new PeriodicTablePage();
|
|
periodicTablePage.SetController(_dataController);
|
|
|
|
var mainContent = _mainWindow.FindControl<ContentControl>("MainContent");
|
|
if (mainContent != null)
|
|
{
|
|
mainContent.Content = periodicTablePage;
|
|
Logger.Log("NavigationService: Navigation zum Periodensystem");
|
|
}
|
|
else
|
|
{
|
|
Logger.LogError("MainContent Control nicht gefunden");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogException(ex, "NavigateToPeriodicTable");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Navigation zur About-Seite (Interface Implementation)
|
|
/// </summary>
|
|
public void NavigateToAbout()
|
|
{
|
|
try
|
|
{
|
|
if (_dataController == null)
|
|
{
|
|
Logger.LogError("DataController nicht gesetzt");
|
|
return;
|
|
}
|
|
|
|
var aboutPage = new AboutPage();
|
|
aboutPage.SetController(_dataController);
|
|
|
|
var mainContent = _mainWindow.FindControl<ContentControl>("MainContent");
|
|
if (mainContent != null)
|
|
{
|
|
mainContent.Content = aboutPage;
|
|
Logger.Log("NavigationService: Navigation zu About");
|
|
}
|
|
else
|
|
{
|
|
Logger.LogError("MainContent Control nicht gefunden");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogException(ex, "NavigateToAbout");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Navigation zur Landing Page (Interface Implementation)
|
|
/// </summary>
|
|
public void NavigateToLanding()
|
|
{
|
|
try
|
|
{
|
|
if (_dataController == null)
|
|
{
|
|
Logger.LogError("DataController nicht gesetzt");
|
|
return;
|
|
}
|
|
|
|
var landingPage = new LandingPage();
|
|
landingPage.SetController(_dataController);
|
|
|
|
var mainContent = _mainWindow.FindControl<ContentControl>("MainContent");
|
|
if (mainContent != null)
|
|
{
|
|
mainContent.Content = landingPage;
|
|
Logger.Log("NavigationService: Navigation zur Landing Page");
|
|
}
|
|
else
|
|
{
|
|
Logger.LogError("MainContent Control nicht gefunden");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogException(ex, "NavigateToLanding");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Theme-Wechsel (Interface Implementation)
|
|
/// </summary>
|
|
public void ToggleTheme()
|
|
{
|
|
try
|
|
{
|
|
var app = Application.Current;
|
|
if (app != null)
|
|
{
|
|
var currentTheme = app.ActualThemeVariant;
|
|
var newTheme = currentTheme == Avalonia.Styling.ThemeVariant.Dark
|
|
? Avalonia.Styling.ThemeVariant.Light
|
|
: Avalonia.Styling.ThemeVariant.Dark;
|
|
|
|
app.RequestedThemeVariant = newTheme;
|
|
|
|
// Settings speichern
|
|
var settings = new AppSettings
|
|
{
|
|
LastTheme = newTheme.ToString() ?? "Dark",
|
|
LastUsed = DateTime.Now,
|
|
PreferredLanguage = "German"
|
|
};
|
|
DataManager.SaveSettings(settings);
|
|
|
|
Logger.Log($"NavigationService: Theme gewechselt zu {newTheme}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogException(ex, "ToggleTheme");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Export-Bestätigung anzeigen (Interface Implementation)
|
|
/// </summary>
|
|
public void ShowExportConfirmation()
|
|
{
|
|
try
|
|
{
|
|
Logger.Log("NavigationService: Export-Bestätigung angezeigt");
|
|
// Hier könnte ein Dialog oder Notification angezeigt werden
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogException(ex, "ShowExportConfirmation");
|
|
}
|
|
}
|
|
}
|
|
}
|