Compare commits

...

2 Commits

Author SHA1 Message Date
5654ed83ea no changes 2025-06-30 15:30:55 +02:00
60f83f9182 Finished 2025-06-30 15:30:41 +02:00
6 changed files with 171 additions and 347 deletions

0
KOMMENTIERUNGS-STATUS.md Normal file
View File

View File

@ -48,6 +48,18 @@ namespace Project_Periodensystem.Controller
_elements = elements ?? new List<Element>();
}
/// <summary>
/// Extrahiert alle Atomgewichte als Array - demonstriert klassische Array-Erstellung
///
/// C# KONZEPTE:
/// - Array-Initialisierung: new double[size]
/// - For-Schleife: Imperative Programmierung
/// - Property-Zugriff: element.AtomicWeight
///
/// ALTERNATIVE (LINQ): return _elements.Select(e => e.AtomicWeight).ToArray();
/// Zeigt Unterschied zwischen imperativem und funktionalem Stil
/// </summary>
/// <returns>Array aller Atomgewichte in g/mol</returns>
public double[] GetAtomicWeights()
{
double[] weights = new double[_elements.Count];
@ -58,6 +70,17 @@ namespace Project_Periodensystem.Controller
return weights;
}
/// <summary>
/// Berechnet das durchschnittliche Atomgewicht aller Elemente
///
/// C# KONZEPTE:
/// - Early Return Pattern: if (!_elements.Any()) return 0.0;
/// - Method Reuse: Nutzt GetAtomicWeights()
/// - Klassische Iteration: for-Schleife für Summe
///
/// MATHEMATIK: Arithmetisches Mittel = Summe / Anzahl
/// </summary>
/// <returns>Durchschnittliches Atomgewicht oder 0.0 bei leerer Liste</returns>
public double GetAverageAtomicWeight()
{
if (!_elements.Any()) return 0.0;
@ -71,15 +94,39 @@ namespace Project_Periodensystem.Controller
return sum / weights.Length;
}
/// <summary>
/// Sammelt alle einzigartigen Element-Serien - demonstriert LINQ-Pipeline
///
/// C# KONZEPTE:
/// - LINQ Select(): Projektion (e => e.Series)
/// - LINQ Distinct(): Entfernt Duplikate
/// - LINQ Where(): Filtert leere/null Werte
/// - LINQ OrderBy(): Alphabetische Sortierung
/// - Method Chaining: Verkettung mehrerer Operationen
///
/// RÜCKGABE: Sortierte Liste aller chemischen Serien
/// </summary>
/// <returns>Liste aller Element-Serien (Alkalimetall, Edelgas, etc.)</returns>
public List<string> GetAllSeries()
{
return _elements.Select(e => e.Series)
.Distinct()
.Where(s => !string.IsNullOrWhiteSpace(s))
.OrderBy(s => s)
.ToList();
return _elements.Select(e => e.Series) // Projektion
.Distinct() // Duplikate entfernen
.Where(s => !string.IsNullOrWhiteSpace(s)) // Null/Empty filtern
.OrderBy(s => s) // Alphabetisch sortieren
.ToList(); // Zu Liste konvertieren
}
/// <summary>
/// Sammelt wichtige Statistiken in einem Tuple - demonstriert strukturierte Rückgaben
///
/// C# KONZEPTE:
/// - Tuple Return Type: (int, int, double)
/// - Method Delegation: Ruft andere Methoden auf
/// - Tuple Creation: (value1, value2, value3)
///
/// VERWENDUNG: var (total, series, avg) = statistics.GetStatistics();
/// </summary>
/// <returns>Tuple mit (Anzahl Elemente, Anzahl Serien, Durchschnittsgewicht)</returns>
public (int totalElements, int uniqueSeries, double avgWeight) GetStatistics()
{
var seriesCount = GetAllSeries().Count;
@ -88,6 +135,18 @@ namespace Project_Periodensystem.Controller
return (_elements.Count, seriesCount, avgWeight);
}
/// <summary>
/// Findet das leichteste und schwerste Element - demonstriert LINQ Ordering
///
/// C# KONZEPTE:
/// - LINQ OrderBy() / OrderByDescending(): Sortierung
/// - LINQ First(): Erstes Element nach Sortierung
/// - Tuple mit nullable Types: (Element?, Element?)
/// - Guard Clause: Early return bei leerer Liste
///
/// CHEMIE: Wasserstoff ist leichtestes (1.008), schwerste variieren
/// </summary>
/// <returns>Tuple mit (leichtestes Element, schwerstes Element) oder (null, null)</returns>
public (Element? lightest, Element? heaviest) GetWeightExtremes()
{
if (!_elements.Any()) return (null, null);
@ -98,6 +157,18 @@ namespace Project_Periodensystem.Controller
return (lightest, heaviest);
}
/// <summary>
/// Extrahiert Element-Informationen nach Ordnungszahl - demonstriert Tuple-basierte APIs
///
/// C# KONZEPTE:
/// - LINQ FirstOrDefault(): Sichere Suche (kann null zurückgeben)
/// - Conditional Operator: condition ? trueValue : falseValue
/// - Tuple mit Mixed Types: (string, string, double)
///
/// FALLBACK: Bei nicht gefundenem Element ("?", "Unknown", 0.0)
/// </summary>
/// <param name="atomicNumber">Ordnungszahl des gesuchten Elements (1-118)</param>
/// <returns>Tuple mit (Symbol, Name, Atomgewicht)</returns>
public (string symbol, string name, double weight) GetElementInfo(int atomicNumber)
{
var element = _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber);
@ -106,6 +177,18 @@ namespace Project_Periodensystem.Controller
: ("?", "Unknown", 0.0);
}
/// <summary>
/// Ermittelt die Position eines Elements im Periodensystem-Grid
///
/// C# KONZEPTE:
/// - Konsistente API: Gleiche Suchmuster wie GetElementInfo()
/// - Tuple für Koordinaten: (int row, int column)
/// - Fallback-Werte: (-1, -1) für "nicht gefunden"
///
/// VERWENDUNG: var (row, col) = statistics.GetElementPosition(1); // Wasserstoff
/// </summary>
/// <param name="atomicNumber">Ordnungszahl des gesuchten Elements</param>
/// <returns>Tuple mit (Zeile, Spalte) oder (-1, -1) wenn nicht gefunden</returns>
public (int row, int column) GetElementPosition(int atomicNumber)
{
var element = _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber);

View File

@ -7,42 +7,21 @@ using Project_Periodensystem.Persistence;
namespace Project_Periodensystem.Controller
{
/// <summary>
/// Haupt-Controller für das Periodensystem - implementiert das MVC-Pattern
///
/// ZWECK UND ARCHITEKTUR:
/// - Zentrale Kontrollschicht zwischen View (UI) und Model/Persistence (Daten)
/// - Koordiniert alle Geschäftslogik-Operationen für das Periodensystem
/// - Delegiert komplexe Aufgaben an spezialisierte Helper-Klassen (Single Responsibility Principle)
/// - Bietet eine einheitliche API für alle UI-Komponenten
///
/// DESIGN PATTERN:
/// - MVC (Model-View-Controller): Trennt Präsentation von Geschäftslogik
/// - Delegation Pattern: Überträgt Verantwortlichkeiten an spezialisierte Klassen
/// - Dependency Injection: Nimmt INavigationService als abhängige Komponente entgegen
///
/// C# KONZEPTE:
/// - Nullable Reference Types (INavigationService?, ElementValidator?)
/// - LINQ für Datenoperationen (FirstOrDefault, Where, ToArray)
/// - Exception Handling mit try-catch-Blöcken
/// - Lambda Expressions für Delegation an Helper-Klassen
/// - Tuple-Rückgabewerte für strukturierte Daten
/// Haupt-Controller für das Periodensystem - implementiert MVC-Pattern.
/// Koordiniert Geschäftslogik zwischen View und Model/Persistence.
/// Delegiert komplexe Aufgaben an spezialisierte Helper-Klassen.
/// </summary>
public class PeriodensystemController
{
// ===== PRIVATE FELDER =====
/// <summary>
/// Zentrale Liste aller chemischen Elemente
/// List&lt;T&gt; ermöglicht dynamisches Hinzufügen/Entfernen von Elementen
/// Private Field mit Underscore-Notation (_elements) nach C#-Konvention
/// Liste aller chemischen Elemente
/// </summary>
private List<Element> _elements = new List<Element>();
/// <summary>
/// Navigation Service für Seitenwechsel in der Avalonia-Anwendung
/// Readonly: Kann nur im Konstruktor zugewiesen werden (Immutability)
/// Nullable (?): Kann null sein, da Navigation optional ist
/// Interface-basiert: Ermöglicht verschiedene Implementierungen (Dependency Inversion)
/// Navigation Service für Seitenwechsel (optional, da Interface-basiert)
/// </summary>
private readonly INavigationService? _navigationService;
@ -63,22 +42,8 @@ namespace Project_Periodensystem.Controller
private ElementStatistics? _statistics;
// ===== KONSTRUKTOR =====
/// <summary>
/// Konstruktor mit optionaler Dependency Injection
///
/// PARAMETER:
/// - navigationService: Optional (null by default), ermöglicht Navigation zwischen Seiten
///
/// C# FEATURES:
/// - Default Parameter (= null): Macht den Parameter optional
/// - Nullable Reference Types: navigationService kann null sein
/// - Constructor Chaining: Ruft LoadElements() zur Initialisierung auf
///
/// ABLAUF:
/// 1. Navigation Service speichern (kann null sein)
/// 2. Elemente aus Persistence-Layer laden
/// 3. Helper-Klassen mit geladenen Daten initialisieren
/// Konstruktor mit optionaler Navigation
/// </summary>
public PeriodensystemController(INavigationService? navigationService = null)
{
@ -86,52 +51,28 @@ namespace Project_Periodensystem.Controller
LoadElements(); // Daten sofort beim Erstellen laden
}
// ===== PRIVATE INITIALISIERUNGSMETHODEN =====
/// <summary>
/// Lädt alle chemischen Elemente aus dem Persistence-Layer
///
/// ZWECK:
/// - Zentrale Initialisierung aller Elementdaten
/// - Fehlerbehandlung beim Laden der Daten
/// - Initialisierung der Helper-Klassen nach erfolgreichem Laden
/// - Ausführliches Logging für Debugging und Monitoring
///
/// C# KONZEPTE:
/// - Exception Handling: try-catch für robuste Fehlerbehandlung
/// - LINQ: Take(10) für die ersten 10 Elemente
/// - Tuple Deconstruction: (totalElements, uniqueSeries, avgWeight) = GetStatistics()
/// - Null-Conditional Operator: lightest?.Symbol verhindert NullReferenceException
/// - String Interpolation: $"Text {variable}" für lesbare Ausgaben
///
/// FEHLERBEHANDLUNG:
/// - Bei Exceptions wird eine leere Liste initialisiert (Graceful Degradation)
/// - Alle Fehler werden geloggt für spätere Analyse
/// Lädt alle chemischen Elemente und initialisiert Helper-Klassen
/// </summary>
private void LoadElements()
{
try
{
// Elemente aus DataManager laden (Persistence Layer)
// Elemente aus DataManager laden
_elements = DataManager.LoadElements();
Logger.Log($"Controller: {_elements.Count} Elemente erfolgreich geladen (via DataManager)");
Logger.Log($"Controller: {_elements.Count} Elemente erfolgreich geladen");
// Helper-Klassen mit den geladenen Daten initialisieren
// Delegation Pattern: Spezialisierte Klassen für verschiedene Aufgaben
// Helper-Klassen initialisieren
_validator = new ElementValidator(_elements);
_statistics = new ElementStatistics(_elements);
// ===== DEMONSTRATIVE LOGGING VON C#-FEATURES =====
// Arrays: Alle Element-Symbole als Array
// Demonstrative Logging der geladenen Daten
var symbols = GetAllSymbols();
Logger.LogArray("Element-Symbole (erste 10)", symbols.Take(10).ToArray());
// Tuples: Strukturierte Rückgabe mehrerer Werte
var (totalElements, uniqueSeries, avgWeight) = GetStatistics();
Logger.LogTuple("Statistiken", $"Elemente: {totalElements}, Serien: {uniqueSeries}, Ø-Gewicht: {avgWeight:F2}");
// Tuples mit Objekten: Extremwerte finden
var (lightest, heaviest) = GetWeightExtremes();
if (lightest != null && heaviest != null)
{

View File

@ -1,76 +1,25 @@
namespace Project_Periodensystem.Model
{
/// <summary>
/// Repräsentiert ein chemisches Element im Periodensystem
///
/// ZWECK UND DATENMODELL:
/// - Zentrale Datenstruktur für alle Elementinformationen
/// - Kapselt alle relevanten chemischen Eigenschaften
/// - Bildet die Grundlage für Periodensystem-Darstellung und -Berechnungen
///
/// DESIGN PRINCIPLES:
/// - Data Transfer Object (DTO): Reine Datenklasse ohne Geschäftslogik
/// - Immutable nach Konstruktion: Alle Properties haben nur Setter (könnten readonly sein)
/// - Rich Object: Enthält alle relevanten Eigenschaften in einer Klasse
///
/// C# KONZEPTE:
/// - Auto-Properties: { get; set; } automatische Getter/Setter
/// - Constructor mit mehreren Parametern: Vollständige Initialisierung
/// - Value Types (int, double): Primitive Datentypen für Zahlen
/// - Reference Types (string): Referenzdatentypen für Text
///
/// VERWENDUNG IM PERIODENSYSTEM:
/// - Gespeichert in List&lt;Element&gt; Collections
/// - Sortiert nach AtomicNumber für Periodensystem-Darstellung
/// - Gruppiert nach Series für chemische Klassifizierung
/// - Positioniert nach Row/Column im UI-Grid
/// Repräsentiert ein chemisches Element im Periodensystem.
/// Zentrale Datenstruktur für alle Elementinformationen und -eigenschaften.
/// </summary>
public class Element
{
// ===== IDENTIFIKATIONS-EIGENSCHAFTEN =====
/// <summary>
/// Ordnungszahl (Protonenzahl) des Elements
///
/// CHEMISCHE BEDEUTUNG:
/// - Eindeutige Identifikation jedes Elements (1-118)
/// - Bestimmt Position im Periodensystem
/// - Entspricht der Anzahl Protonen im Atomkern
///
/// BEISPIELE:
/// - 1 = Wasserstoff (H)
/// - 6 = Kohlenstoff (C)
/// - 79 = Gold (Au)
/// Ordnungszahl (Protonenzahl) des Elements - eindeutige Identifikation (1-118)
/// </summary>
public int AtomicNumber { get; set; }
/// <summary>
/// Chemisches Symbol (Kurzbezeichnung) des Elements
///
/// KONVENTIONEN:
/// - 1-2 Buchstaben, erster Buchstabe groß
/// - Oft lateinischen/griechischen Ursprungs
/// - International standardisiert (IUPAC)
///
/// BEISPIELE:
/// - "H" = Hydrogen (Wasserstoff)
/// - "Au" = Aurum (Gold)
/// - "Fe" = Ferrum (Eisen)
/// Chemisches Symbol (z.B. H, C, Au) - kurze Bezeichnung (1-2 Buchstaben)
/// </summary>
public string Symbol { get; set; }
/// <summary>
/// Vollständiger wissenschaftlicher Name des Elements
///
/// NAMENSGEBUNG:
/// - Offizielle IUPAC-Bezeichnung
/// - Meist englische Namen in der internationalen Wissenschaft
/// - Historische, mythologische oder wissenschaftliche Herkunft
///
/// BEISPIELE:
/// - "Hydrogen" (griechisch: Wasser-bildend)
/// - "Californium" (nach Kalifornien benannt)
/// - "Einstein­ium" (nach Albert Einstein)
/// </summary>
public string ElementName { get; set; }
@ -78,154 +27,62 @@ namespace Project_Periodensystem.Model
/// <summary>
/// Relative Atommasse in atomaren Masseneinheiten (u)
///
/// CHEMISCHE BEDEUTUNG:
/// - Durchschnittliche Masse aller Isotope eines Elements
/// - Gewichtet nach natürlicher Häufigkeit der Isotope
/// - Basis für stöchiometrische Berechnungen
///
/// EINHEIT: u (atomic mass unit)
/// - 1 u ≈ 1.66054 × 10⁻²⁷ kg
/// - Relative Skala (Kohlenstoff-12 = 12.000 u)
///
/// BEISPIELE:
/// - Wasserstoff: ~1.008 u
/// - Kohlenstoff: ~12.011 u
/// - Uran: ~238.029 u
/// </summary>
public double AtomicWeight { get; set; }
/// <summary>
/// Elektronegativität nach Pauling-Skala
///
/// CHEMISCHE BEDEUTUNG:
/// - Fähigkeit eines Atoms, Bindungselektronen anzuziehen
/// - Bestimmt Art der chemischen Bindung (ionisch vs. kovalent)
/// - Wichtig für Vorhersage chemischer Reaktionen
///
/// PAULING-SKALA:
/// - Dimensionslose Größe von 0.7 bis 4.0
/// - Fluor hat den höchsten Wert (4.0)
/// - Trends: Steigt in Perioden von links nach rechts
///
/// BEISPIELE:
/// - Fluor: 4.0 (höchste Elektronegativität)
/// - Sauerstoff: 3.5
/// - Wasserstoff: 2.1
/// - Cäsium: 0.7 (niedrigste)
/// Elektronegativität nach Pauling-Skala (0.7 bis 4.0)
/// </summary>
public double Electronegativity { get; set; }
/// <summary>
/// Dichte bei Standardbedingungen in g/cm³
///
/// PHYSIKALISCHE BEDEUTUNG:
/// - Masse pro Volumeneinheit
/// - Abhängig von Atomgröße und Kristallstruktur
/// - Wichtig für technische Anwendungen
///
/// TRENDS IM PERIODENSYSTEM:
/// - Generell zunehmend mit steigender Ordnungszahl
/// - Maximum bei Osmium (~22.6 g/cm³)
/// - Gase haben sehr geringe Dichten
///
/// BEISPIELE:
/// - Wasserstoff (Gas): ~0.0000899 g/cm³
/// - Wasser (Referenz): 1.0 g/cm³
/// - Gold: ~19.3 g/cm³
/// - Osmium: ~22.6 g/cm³ (dichtestes Element)
/// </summary>
public double Density { get; set; }
// ===== KLASSIFIKATIONS-EIGENSCHAFTEN =====
/// <summary>
/// Chemische Serie/Gruppe des Elements
///
/// KLASSIFIKATION:
/// - Gruppiert Elemente nach ähnlichen chemischen Eigenschaften
/// - Basis für Periodensystem-Farben und -Organisation
/// - Ermöglicht Vorhersage chemischen Verhaltens
///
/// WICHTIGE SERIEN:
/// - "Alkali metal": Li, Na, K, Rb, Cs, Fr (sehr reaktiv)
/// - "Noble gas": He, Ne, Ar, Kr, Xe, Rn (inert)
/// - "Halogen": F, Cl, Br, I, At (7 Valenzelektronen)
/// - "Transition metal": Fe, Cu, Au, etc. (d-Block)
/// - "Lanthanoid": Seltene Erden (f-Block)
///
/// UI-VERWENDUNG:
/// - Farbkodierung im Periodensystem
/// - Filterung und Gruppierung
/// - Tooltip-Informationen
/// Chemische Serie/Gruppe für Klassifikation und UI-Farbkodierung
/// </summary>
public string Series { get; set; }
// ===== POSITIONIERUNGS-EIGENSCHAFTEN =====
/// <summary>
/// Zeile (Periode) im Periodensystem
///
/// CHEMISCHE BEDEUTUNG:
/// - Entspricht der Anzahl Elektronenschalen
/// - Bestimmt vertikale Position im Periodensystem
/// - 1-7 für natürliche Elemente
///
/// TRENDS:
/// - Atomradius nimmt innerhalb einer Periode ab
/// - Ionisierungsenergie steigt innerhalb einer Periode
/// Zeile (Periode) im Periodensystem (1-7)
/// </summary>
public int Row { get; set; }
/// <summary>
/// Spalte (Gruppe) im Periodensystem
///
/// CHEMISCHE BEDEUTUNG:
/// - Entspricht der Anzahl Valenzelektronen (vereinfacht)
/// - Bestimmt horizontale Position im Periodensystem
/// - 1-18 nach IUPAC-Nummerierung
///
/// TRENDS:
/// - Elemente derselben Gruppe haben ähnliche Eigenschaften
/// - Chemische Reaktivität folgt Gruppenmustern
/// Spalte (Gruppe) im Periodensystem (1-18)
/// </summary>
public int Column { get; set; }
// ===== KONSTRUKTOR =====
/// <summary>
/// Vollständiger Konstruktor für die Erstellung eines Element-Objekts
///
/// ZWECK:
/// - Stellt sicher, dass alle Eigenschaften beim Erstellen gesetzt werden
/// - Verhindert unvollständig initialisierte Element-Objekte
/// - Ermöglicht direkte Erstellung aus Datenquellen (CSV, JSON, Database)
///
/// C# KONZEPTE:
/// - Constructor Overloading: Könnte mehrere Konstruktoren haben
/// - Parameter Validation: Könnte Validierung der Eingabewerte enthalten
/// - Immutable Object: Nach Konstruktion unveränderlich (wenn Properties readonly wären)
///
/// PARAMETER:
/// - Alle 9 Eigenschaften müssen beim Erstellen angegeben werden
/// - Reihenfolge entspricht logischer Gruppierung (ID, Name, Physik, Position)
///
/// VERWENDUNG:
/// var hydrogen = new Element(1, "H", "Hydrogen", 1.008, 2.1, 0.0000899, "Nonmetal", 1, 1);
/// Konstruktor - erstellt Element-Objekt mit allen erforderlichen Eigenschaften
/// </summary>
/// <param name="atomicNumber">Ordnungszahl (1-118)</param>
/// <param name="symbol">Chemisches Symbol (z.B. "H", "Au")</param>
/// <param name="elementname">Vollständiger Elementname</param>
/// <param name="atomicWeight">Atommasse in u</param>
/// <param name="electronegativity">Elektronegativität (Pauling-Skala)</param>
/// <param name="density">Dichte in g/cm³</param>
/// <param name="series">Chemische Serie/Gruppe</param>
/// <param name="row">Periodensystem-Zeile</param>
/// <param name="column">Periodensystem-Spalte</param>
public Element(int atomicNumber, string symbol, string elementname, double atomicWeight,
double electronegativity, double density, string series, int row, int column)
{
// Eigenschafts-Zuweisungen mit Selbst-Dokumentation
AtomicNumber = atomicNumber; // Eindeutige Identifikation
Symbol = symbol; // Kurze chemische Bezeichnung
ElementName = elementname; // Vollständiger Name
AtomicWeight = atomicWeight; // Relative Atommasse
Electronegativity = electronegativity; // Bindungsverhalten
Density = density; // Physikalische Eigenschaft
Series = series; // Chemische Klassifikation
Row = row; // Periodensystem-Position vertikal
Column = column; // Periodensystem-Position horizontal
AtomicNumber = atomicNumber;
Symbol = symbol;
ElementName = elementname;
AtomicWeight = atomicWeight;
Electronegativity = electronegativity;
Density = density;
Series = series;
Row = row;
Column = column;
}
}
}

View File

@ -6,26 +6,43 @@ using Project_Periodensystem.Controller;
namespace Project_Periodensystem.View
{
/// <summary>
/// MainWindow mit sauberem MVC-Pattern und Interface-basierter Navigation
/// Hauptfenster der Avalonia-Anwendung - implementiert MVC-Pattern.
/// Koordiniert NavigationService und PeriodensystemController.
/// Löst zirkuläre Abhängigkeiten durch zweistufige Initialisierung.
/// </summary>
public partial class MainWindow : Window
{
/// <summary>
/// Hauptbereich für Seitenwechsel zwischen PeriodicTablePage, AboutPage, etc.
/// </summary>
private ContentControl? mainContent;
/// <summary>
/// Zentrale Geschäftslogik für Periodensystem-Daten und -Operationen
/// </summary>
private readonly PeriodensystemController _dataController;
/// <summary>
/// Service für Navigation zwischen verschiedenen Anwendungsseiten
/// </summary>
private readonly NavigationService _navigationService;
/// <summary>
/// Konstruktor - initialisiert Avalonia-Komponenten und MVC-Architektur
/// </summary>
public MainWindow()
{
InitializeComponent();
InitializeComponent(); // Avalonia UI initialisieren
mainContent = this.FindControl<ContentControl>("MainContent");
// Erstelle Navigation Service mit this (MainWindow)
// Zweistufige Initialisierung wegen zirkulärer Abhängigkeiten:
// 1. NavigationService mit MainWindow erstellen
_navigationService = new NavigationService(this);
// Controller mit Navigation Service initialisieren (Dependency Injection)
// 2. Controller mit NavigationService erstellen
_dataController = new PeriodensystemController(_navigationService);
// Data Controller an Navigation Service setzen
// 3. Controller an NavigationService zurückgeben (löst Zirkularität)
_navigationService.SetDataController(_dataController);
// Landing Page anzeigen

View File

@ -8,130 +8,48 @@ 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
/// Implementiert die Navigation zwischen verschiedenen Seiten der Avalonia-Anwendung.
/// Trennt die Navigation-Logik (WAS) vom UI-Framework (WIE) durch Interface-Implementation.
/// Löst zirkuläre Abhängigkeiten durch zweistufige Initialisierung.
/// </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
/// Referenz zum Hauptfenster für Navigation zwischen Seiten
/// </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
/// Data Controller für Datenzugriff (wird nach Konstruktion gesetzt)
/// </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
/// Initialisiert den NavigationService mit dem Hauptfenster
/// </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");
Logger.Log("NavigationService initialisiert");
}
/// <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");
Logger.Log("DataController in NavigationService gesetzt");
}
/// <summary>
/// Navigation zum Periodensystem (Interface Implementation)
/// Navigation zum Periodensystem - zeigt PeriodicTablePage im MainContent an
/// </summary>
public void NavigateToPeriodicTable()
{
@ -143,9 +61,11 @@ namespace Project_Periodensystem.View
return;
}
// PeriodicTablePage erstellen und Controller setzen
var periodicTablePage = new PeriodicTablePage();
periodicTablePage.SetController(_dataController);
// MainContent Control finden und neue Seite anzeigen
var mainContent = _mainWindow.FindControl<ContentControl>("MainContent");
if (mainContent != null)
{
@ -164,7 +84,7 @@ namespace Project_Periodensystem.View
}
/// <summary>
/// Navigation zur About-Seite (Interface Implementation)
/// Navigation zur About-Seite - zeigt Projektinformationen und Credits
/// </summary>
public void NavigateToAbout()
{
@ -176,9 +96,11 @@ namespace Project_Periodensystem.View
return;
}
// AboutPage erstellen und Controller setzen
var aboutPage = new AboutPage();
aboutPage.SetController(_dataController);
// MainContent Control finden und neue Seite anzeigen
var mainContent = _mainWindow.FindControl<ContentControl>("MainContent");
if (mainContent != null)
{
@ -197,7 +119,7 @@ namespace Project_Periodensystem.View
}
/// <summary>
/// Navigation zur Landing Page (Interface Implementation)
/// Navigation zur Landing Page - Startseite der Anwendung
/// </summary>
public void NavigateToLanding()
{
@ -209,9 +131,11 @@ namespace Project_Periodensystem.View
return;
}
// LandingPage erstellen und Controller setzen
var landingPage = new LandingPage();
landingPage.SetController(_dataController);
// MainContent Control finden und neue Seite anzeigen
var mainContent = _mainWindow.FindControl<ContentControl>("MainContent");
if (mainContent != null)
{
@ -230,7 +154,7 @@ namespace Project_Periodensystem.View
}
/// <summary>
/// Theme-Wechsel (Interface Implementation)
/// Wechselt zwischen Dark- und Light-Theme der Avalonia-Anwendung
/// </summary>
public void ToggleTheme()
{
@ -239,14 +163,16 @@ namespace Project_Periodensystem.View
var app = Application.Current;
if (app != null)
{
// Aktuelles Theme ermitteln und umschalten
var currentTheme = app.ActualThemeVariant;
var newTheme = currentTheme == Avalonia.Styling.ThemeVariant.Dark
? Avalonia.Styling.ThemeVariant.Light
: Avalonia.Styling.ThemeVariant.Dark;
// Neues Theme anwenden
app.RequestedThemeVariant = newTheme;
// Settings speichern
// Theme-Einstellung persistent speichern
var settings = new AppSettings
{
LastTheme = newTheme.ToString() ?? "Dark",
@ -265,14 +191,14 @@ namespace Project_Periodensystem.View
}
/// <summary>
/// Export-Bestätigung anzeigen (Interface Implementation)
/// Zeigt eine Export-Bestätigung an (aktuell nur Logging)
/// </summary>
public void ShowExportConfirmation()
{
try
{
Logger.Log("NavigationService: Export-Bestätigung angezeigt");
// Hier könnte ein Dialog oder Notification angezeigt werden
// TODO: Hier könnte ein Dialog oder Notification angezeigt werden
}
catch (Exception ex)
{