diff --git a/Project_Periodensystem.Controller/ElementStatistics.cs b/Project_Periodensystem.Controller/ElementStatistics.cs
new file mode 100644
index 0000000..c7d6d02
--- /dev/null
+++ b/Project_Periodensystem.Controller/ElementStatistics.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Project_Periodensystem.Model;
+
+namespace Project_Periodensystem.Controller
+{
+ ///
+ /// ElementStatistics - Spezialisierte Klasse für statistische Berechnungen und Datenanalyse
+ ///
+ /// Diese Klasse wurde aus dem Haupt-Controller ausgelagert, um das Single Responsibility
+ /// Principle zu befolgen. Sie konzentriert sich ausschließlich auf:
+ ///
+ /// - Mathematische Berechnungen (Durchschnitte, Extreme)
+ /// - Datengruppierung und -analyse (Serien, Kategorien)
+ /// - Informationsextraktion (Tuple-basierte Abfragen)
+ /// - Performance-optimierte LINQ-Operationen
+ ///
+ /// Vorteile der Auslagerung:
+ /// - Bessere Testbarkeit einzelner Berechnungen
+ /// - Wiederverwendbarkeit der Statistik-Funktionen
+ /// - Klare Trennung von UI-Logik und Datenverarbeitung
+ /// - Einfache Erweiterung um neue Statistiken
+ ///
+ public class ElementStatistics
+ {
+ ///
+ /// Private, schreibgeschützte Liste aller Elemente für statistische Berechnungen.
+ /// Wird im Konstruktor gesetzt und bleibt danach unveränderlich (readonly).
+ /// Garantiert Datenintegrität während der gesamten Lebensdauer des Objekts.
+ ///
+ private readonly List _elements;
+
+ ///
+ /// Konstruktor der ElementStatistics-Klasse.
+ /// Initialisiert die Statistik-Engine mit einer Element-Sammlung.
+ ///
+ /// Design-Prinzipien:
+ /// - Dependency Injection: Element-Liste wird von außen bereitgestellt
+ /// - Defensive Programmierung: Null-Safety durch Fallback
+ /// - Unveränderlichkeit: readonly field für Datensicherheit
+ ///
+ /// Liste der Elemente für statistische Auswertungen (kann null sein)
+ public ElementStatistics(List elements)
+ {
+ // Null-Safety: Falls null übergeben wird, erstelle eine leere Liste
+ // Verhindert NullReferenceExceptions in allen nachfolgenden Methoden
+ _elements = elements ?? new List();
+ }
+
+ public double[] GetAtomicWeights()
+ {
+ double[] weights = new double[_elements.Count];
+ for (int i = 0; i < _elements.Count; i++)
+ {
+ weights[i] = _elements[i].AtomicWeight;
+ }
+ return weights;
+ }
+
+ public double GetAverageAtomicWeight()
+ {
+ if (!_elements.Any()) return 0.0;
+
+ double[] weights = GetAtomicWeights();
+ double sum = 0;
+ for (int i = 0; i < weights.Length; i++)
+ {
+ sum += weights[i];
+ }
+ return sum / weights.Length;
+ }
+
+ public List GetAllSeries()
+ {
+ return _elements.Select(e => e.Series)
+ .Distinct()
+ .Where(s => !string.IsNullOrWhiteSpace(s))
+ .OrderBy(s => s)
+ .ToList();
+ }
+
+ public (int totalElements, int uniqueSeries, double avgWeight) GetStatistics()
+ {
+ var seriesCount = GetAllSeries().Count;
+ var avgWeight = GetAverageAtomicWeight();
+
+ return (_elements.Count, seriesCount, avgWeight);
+ }
+
+ public (Element? lightest, Element? heaviest) GetWeightExtremes()
+ {
+ if (!_elements.Any()) return (null, null);
+
+ var lightest = _elements.OrderBy(e => e.AtomicWeight).First();
+ var heaviest = _elements.OrderByDescending(e => e.AtomicWeight).First();
+
+ return (lightest, heaviest);
+ }
+
+ public (string symbol, string name, double weight) GetElementInfo(int atomicNumber)
+ {
+ var element = _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber);
+ return element != null
+ ? (element.Symbol, element.ElementName, element.AtomicWeight)
+ : ("?", "Unknown", 0.0);
+ }
+
+ public (int row, int column) GetElementPosition(int atomicNumber)
+ {
+ var element = _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber);
+ return element != null ? (element.Row, element.Column) : (-1, -1);
+ }
+ }
+}
diff --git a/Project_Periodensystem.Controller/ElementValidator.cs b/Project_Periodensystem.Controller/ElementValidator.cs
new file mode 100644
index 0000000..f0de7a8
--- /dev/null
+++ b/Project_Periodensystem.Controller/ElementValidator.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Project_Periodensystem.Model;
+
+namespace Project_Periodensystem.Controller
+{
+ ///
+ /// ElementValidator - Spezialisierte Klasse für Datenvalidierung
+ ///
+ /// Diese Klasse wurde aus dem PeriodensystemController ausgelagert, um das
+ /// Single Responsibility Principle (SRP) zu befolgen. Sie ist ausschließlich
+ /// für die Validierung von Element-Daten zuständig.
+ ///
+ /// Vorteile der Auslagerung:
+ /// - Bessere Testbarkeit (kann isoliert getestet werden)
+ /// - Klarere Verantwortlichkeiten
+ /// - Wiederverwendbarkeit in anderen Controllern
+ /// - Einfachere Wartung und Erweiterung
+ ///
+ public class ElementValidator
+ {
+ // Private readonly Liste der zu validierenden Elemente
+ // readonly = kann nach Initialisierung nicht mehr geändert werden
+ private readonly List _elements;
+
+ ///
+ /// Konstruktor - Initialisiert den Validator mit einer Element-Liste
+ ///
+ /// Liste der zu validierenden Elemente
+ public ElementValidator(List elements)
+ {
+ // Null-Check mit Fallback zu leerer Liste - verhindert NullReferenceExceptions
+ _elements = elements ?? new List();
+ }
+
+ ///
+ /// Führt eine umfassende Validierung der Element-Daten durch.
+ ///
+ /// Diese Methode prüft verschiedene Datenintegritäts-Aspekte:
+ /// 1. Existenz von Elementen (leere Liste = Problem)
+ /// 2. Eindeutigkeit der Atomnummern (jede darf nur einmal vorkommen)
+ /// 3. Vollständigkeit der Element-Symbole (keine leeren/null Werte)
+ ///
+ /// Verwendet moderne C# LINQ-Syntax für effiziente Datenabfragen:
+ /// - GroupBy() für Gruppierung nach Atomnummer
+ /// - Where() für Filterung
+ /// - Any() für Existenzprüfung
+ /// - Count() für Anzahl-Ermittlung
+ ///
+ /// true = alle Validierungen bestanden, false = Fehler gefunden
+ public bool ValidateData()
+ {
+ // Erste Prüfung: Sind überhaupt Elemente vorhanden?
+ // Any() ist effizienter als Count() > 0, da es beim ersten Element stoppt
+ if (!_elements.Any())
+ {
+ Logger.Log("Keine Elemente zum Validieren");
+ return false;
+ }
+
+ // Zweite Prüfung: Doppelte Atomnummern aufspüren
+ // LINQ-Chain: GroupBy sammelt Elemente mit gleicher Atomnummer
+ // Where filtert Gruppen mit mehr als einem Element (= Duplikate)
+ // Select extrahiert nur die Atomnummer (Key) für Logging
+ var duplicateNumbers = _elements.GroupBy(e => e.AtomicNumber)
+ .Where(g => g.Count() > 1)
+ .Select(g => g.Key);
+
+ if (duplicateNumbers.Any())
+ {
+ // string.Join() erstellt eine kommaseparierte Liste der doppelten Nummern
+ Logger.Log($"Doppelte Atomnummern gefunden: {string.Join(", ", duplicateNumbers)}");
+ return false;
+ }
+
+ // Dritte Prüfung: Leere oder ungültige Element-Symbole finden
+ // string.IsNullOrWhiteSpace() prüft auf null, leer oder nur Leerzeichen
+ var emptySymbols = _elements.Where(e => string.IsNullOrWhiteSpace(e.Symbol));
+ if (emptySymbols.Any())
+ {
+ Logger.Log($"Elemente mit leeren Symbolen gefunden: {emptySymbols.Count()}");
+ return false;
+ }
+
+ // Alle Validierungen bestanden
+ Logger.Log("Datenvalidierung erfolgreich");
+ return true;
+ }
+
+ ///
+ /// Validiert die Position eines Elements im Periodensystem.
+ ///
+ /// Das Periodensystem hat feste Dimensionen:
+ /// - Zeilen (Perioden): 0-9 (insgesamt 10 Perioden)
+ /// - Spalten (Gruppen): 0-17 (insgesamt 18 Gruppen)
+ ///
+ /// Diese Methode stellt sicher, dass Elemente nur an gültigen Positionen
+ /// platziert werden. Ungültige Positionen würden zu Layout-Fehlern oder
+ /// Abstürzen in der Benutzeroberfläche führen.
+ ///
+ /// Verwendet nullable Reference Types (Element?) - moderne C# 8.0+ Syntax
+ ///
+ /// Das zu prüfende Element (kann null sein)
+ /// true = Position ist gültig, false = Position ungültig oder Element ist null
+ public bool ValidateElementPosition(Element? element)
+ {
+ // Null-Check: Defensive Programmierung verhindert NullReferenceExceptions
+ if (element == null)
+ {
+ Logger.Log("Element ist null");
+ return false;
+ }
+
+ // Positionsgrenzen prüfen: Standard-Periodensystem Layout
+ // Row: 0-9 (Periode 1-10, aber 0-basiert indiziert)
+ // Column: 0-17 (Gruppe 1-18, aber 0-basiert indiziert)
+ if (element.Row < 0 || element.Row > 9 || element.Column < 0 || element.Column > 17)
+ {
+ Logger.Log($"Ungültige Position für {element.Symbol}: Row={element.Row}, Column={element.Column}");
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Führt eine vollständige Validierungsprüfung aller Elemente durch und protokolliert Fehler.
+ ///
+ /// Diese Utility-Methode iteriert durch alle Elemente und prüft jedes einzeln.
+ /// Hauptzweck ist das Debugging und die Qualitätssicherung:
+ /// - Identifiziert problematische Elemente
+ /// - Protokolliert detaillierte Fehlermeldungen
+ /// - Hilfreich bei der Datenbereinigung
+ ///
+ /// Besonderheiten:
+ /// - Verwendet null-conditional operator (?.) für sichere Navigation
+ /// - Null-coalescing operator (??) für Fallback-Werte
+ /// - Moderne C# Syntax für robuste Fehlerbehandlung
+ ///
+ public void LogValidationInfo()
+ {
+ // Iteriere durch alle Elemente und validiere jedes einzeln
+ foreach (var element in _elements)
+ {
+ // Prüfe Position für jedes Element
+ if (!ValidateElementPosition(element))
+ {
+ // element?.Symbol verwendet null-conditional operator
+ // Falls element null ist, wird Symbol nicht abgerufen -> kein Crash
+ // ?? "NULL" ist ein Fallback falls Symbol null/leer ist
+ Logger.Log($"VALIDIERUNGSFEHLER: {element?.Symbol ?? "NULL"}");
+ }
+ }
+ }
+ }
+}
diff --git a/Project_Periodensystem.Controller/INavigationService.cs b/Project_Periodensystem.Controller/INavigationService.cs
index 684471a..2116b2a 100644
--- a/Project_Periodensystem.Controller/INavigationService.cs
+++ b/Project_Periodensystem.Controller/INavigationService.cs
@@ -3,15 +3,86 @@ using System;
namespace Project_Periodensystem.Controller
{
///
- /// Interface für Navigation - trennt Controller von UI-Dependencies
- /// Controller definiert WAS navigiert wird, View definiert WIE
+ /// Navigation Service Interface - Implementiert Dependency Inversion Principle
+ ///
+ /// ZWECK UND ARCHITEKTUR:
+ /// - Entkoppelt Controller-Layer von UI-spezifischen Navigation-Details
+ /// - Ermöglicht verschiedene UI-Implementierungen (WPF, Avalonia, Console, etc.)
+ /// - Macht Controller-Layer testbar durch Mock-Implementierungen
+ /// - Implementiert Interface Segregation Principle (nur notwendige Navigation-Methoden)
+ ///
+ /// DESIGN PATTERNS:
+ /// - Dependency Inversion: Controller abhängig von Abstraktion, nicht von Implementierung
+ /// - Strategy Pattern: Verschiedene Navigation-Strategien möglich
+ /// - Command Pattern: Jede Methode kapselt eine UI-Aktion
+ ///
+ /// C# KONZEPTE:
+ /// - Interface Definition: Vertrag ohne Implementierung
+ /// - Abstraktion: Trennt WHAT (Navigation) von HOW (UI-Framework)
+ /// - Dependency Injection: Controller erhält Implementation via Constructor
+ ///
+ /// IMPLEMENTIERUNG:
+ /// - NavigationService.cs (View-Layer) implementiert dieses Interface
+ /// - Controller ruft Interface-Methoden auf, kennt aber Implementierung nicht
+ /// - Ermöglicht einfaches Testen und verschiedene UI-Frameworks
+ ///
+ /// TESTBARKEIT:
+ /// - Mock-Implementierung für Unit Tests möglich
+ /// - Keine direkten UI-Dependencies im Controller
+ /// - Isolierte Testung der Navigation-Logik
///
public interface INavigationService
{
+ ///
+ /// Navigiert zur Hauptansicht des Periodensystems
+ ///
+ /// IMPLEMENTIERUNG:
+ /// - Zeigt das vollständige, interaktive Periodensystem an
+ /// - Hauptfunktion der Anwendung
+ /// - Alle Element-Tiles werden geladen und angezeigt
+ ///
void NavigateToPeriodicTable();
+
+ ///
+ /// Navigiert zur About/Info-Seite der Anwendung
+ ///
+ /// IMPLEMENTIERUNG:
+ /// - Zeigt Anwendungsinformationen, Version, Credits
+ /// - Dokumentation und Hilfe-Inhalte
+ /// - Links zu weiteren Ressourcen
+ ///
void NavigateToAbout();
+
+ ///
+ /// Navigiert zurück zur Startseite/Hauptmenü
+ ///
+ /// IMPLEMENTIERUNG:
+ /// - Zeigt das Hauptmenü mit Navigation-Optionen
+ /// - Reset-Funktion zum Anwendungsstart
+ /// - Home-Button Funktionalität
+ ///
void NavigateToLanding();
+
+ ///
+ /// Wechselt zwischen hellen und dunklen UI-Themes
+ ///
+ /// IMPLEMENTIERUNG:
+ /// - Toggle zwischen Light/Dark Mode
+ /// - Aktualisiert globale Theme-Settings
+ /// - Persistiert Benutzer-Präferenz
+ /// - Wendet neues Theme auf alle UI-Komponenten an
+ ///
void ToggleTheme();
+
+ ///
+ /// Zeigt Bestätigungsdialog für Datenexport
+ ///
+ /// IMPLEMENTIERUNG:
+ /// - Modal-Dialog mit Export-Optionen
+ /// - Benutzer wählt Format und Ziel
+ /// - Startet Export-Prozess nach Bestätigung
+ /// - Fortschrittsanzeige und Erfolgs-/Fehlermeldungen
+ ///
void ShowExportConfirmation();
}
}
diff --git a/Project_Periodensystem.Controller/PeriodensystemController.cs b/Project_Periodensystem.Controller/PeriodensystemController.cs
index 24b2005..e716743 100644
--- a/Project_Periodensystem.Controller/PeriodensystemController.cs
+++ b/Project_Periodensystem.Controller/PeriodensystemController.cs
@@ -7,48 +7,131 @@ using Project_Periodensystem.Persistence;
namespace Project_Periodensystem.Controller
{
///
- /// Controller für das Periodensystem - verwaltet die Geschäftslogik
- /// und trennt View von Model gemäß MVC-Pattern
- /// SAUBERE ARCHITEKTUR: Verwendet Interface für Navigation
+ /// 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
///
public class PeriodensystemController
{
- // Nullable Field um Warning zu vermeiden
- private List _elements = new List();
-
- // Navigation Service Interface (KEINE direkte UI-Dependency!)
- private readonly INavigationService? _navigationService;
+ // ===== PRIVATE FELDER =====
///
- /// Konstruktor - optional mit Navigation Service
+ /// Zentrale Liste aller chemischen Elemente
+ /// List<T> ermöglicht dynamisches Hinzufügen/Entfernen von Elementen
+ /// Private Field mit Underscore-Notation (_elements) nach C#-Konvention
+ ///
+ private List _elements = new List();
+
+ ///
+ /// 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)
+ ///
+ private readonly INavigationService? _navigationService;
+
+ // ===== HELPER-KLASSEN FÜR CODE-ORGANISATION =====
+
+ ///
+ /// Spezialisierte Klasse für Validierungslogik
+ /// Nullable: Wird erst nach dem Laden der Elemente initialisiert
+ /// Separation of Concerns: Validierung ist getrennt von anderen Aufgaben
+ ///
+ private ElementValidator? _validator;
+
+ ///
+ /// Spezialisierte Klasse für statistische Berechnungen
+ /// Nullable: Wird erst nach dem Laden der Elemente initialisiert
+ /// Single Responsibility: Nur für Statistiken zuständig
+ ///
+ private ElementStatistics? _statistics;
+
+ // ===== KONSTRUKTOR =====
+
+ ///
+ /// 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
///
public PeriodensystemController(INavigationService? navigationService = null)
{
_navigationService = navigationService;
- LoadElements();
+ LoadElements(); // Daten sofort beim Erstellen laden
}
+ // ===== PRIVATE INITIALISIERUNGSMETHODEN =====
+
///
- /// Lädt alle Elemente über den Persistence-Layer (JETZT MIT DATAMANAGER!)
+ /// 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
///
private void LoadElements()
{
try
{
- // NEUE METHODE: DataManager statt direkt PeriodicTableData
+ // Elemente aus DataManager laden (Persistence Layer)
_elements = DataManager.LoadElements();
Logger.Log($"Controller: {_elements.Count} Elemente erfolgreich geladen (via DataManager)");
- // NEUE FEATURES demonstrieren:
- // Array-Operationen testen
+ // Helper-Klassen mit den geladenen Daten initialisieren
+ // Delegation Pattern: Spezialisierte Klassen für verschiedene Aufgaben
+ _validator = new ElementValidator(_elements);
+ _statistics = new ElementStatistics(_elements);
+
+ // ===== DEMONSTRATIVE LOGGING VON C#-FEATURES =====
+
+ // Arrays: Alle Element-Symbole als Array
var symbols = GetAllSymbols();
Logger.LogArray("Element-Symbole (erste 10)", symbols.Take(10).ToArray());
- // Tuple-Operationen testen
+ // Tuples: Strukturierte Rückgabe mehrerer Werte
var (totalElements, uniqueSeries, avgWeight) = GetStatistics();
Logger.LogTuple("Statistiken", $"Elemente: {totalElements}, Serien: {uniqueSeries}, Ø-Gewicht: {avgWeight:F2}");
- // Extremwerte finden
+ // Tuples mit Objekten: Extremwerte finden
var (lightest, heaviest) = GetWeightExtremes();
if (lightest != null && heaviest != null)
{
@@ -58,304 +141,352 @@ namespace Project_Periodensystem.Controller
}
catch (Exception ex)
{
+ // Graceful Degradation: Bei Fehlern eine leere Liste verwenden
Logger.Log($"EXCEPTION in LoadElements: {ex.Message}");
_elements = new List();
+
+ // Helper-Klassen können nicht initialisiert werden (bleiben null)
+ _validator = null;
+ _statistics = null;
}
}
+ // ===== PUBLIC API METHODEN - ELEMENTZUGRIFF =====
+
///
- /// Gibt alle verfügbaren Elemente zurück
+ /// Gibt alle Elemente als List<Element> zurück
+ ///
+ /// RÜCKGABETYP: List<Element>
+ /// - Ermöglicht Add/Remove-Operationen
+ /// - LINQ-Operationen verfügbar
+ /// - Dynamische Größe
+ ///
+ /// VERWENDUNG:
+ /// - Hauptsächlich für UI-Bindungen (WPF/Avalonia DataBinding)
+ /// - Für LINQ-Abfragen in der View-Schicht
///
- /// Liste aller Elemente
public List GetAllElements()
{
return _elements;
}
///
- /// Gibt Elemente als Array zurück (für Array-Operationen)
+ /// Gibt alle Elemente als Array zurück
+ ///
+ /// RÜCKGABETYP: Element[]
+ /// - Feste Größe (Read-Only nach Erstellung)
+ /// - Bessere Performance für Iterationen
+ /// - Weniger Speicher-Overhead als List
+ ///
+ /// C# KONZEPT: LINQ ToArray()
+ /// - Konvertiert IEnumerable zu Array
+ /// - Erstellt eine Kopie der Daten
+ ///
+ /// VERWENDUNG:
+ /// - Für Algorithmen, die feste Arrays benötigen
+ /// - Wenn Unveränderlichkeit wichtig ist
///
- /// Array aller Elemente
public Element[] GetAllElementsAsArray()
{
return _elements.ToArray();
}
///
- /// Gibt nur die Symbole als String-Array zurück
+ /// Extrahiert alle Element-Symbole als String-Array
+ ///
+ /// ZWECK:
+ /// - Demonstriert klassische Array-Initialisierung und -Population
+ /// - Zeigt manuelle Iteration vs. LINQ-Alternativen
+ ///
+ /// C# KONZEPTE:
+ /// - Array-Initialisierung: new string[size]
+ /// - For-Schleifen: Klassische imperative Programmierung
+ /// - Array-Indexing: array[i] = value
+ ///
+ /// ALTERNATIVE (LINQ):
+ /// return _elements.Select(e => e.Symbol).ToArray();
+ ///
+ /// LERNWERT:
+ /// - Zeigt Unterschied zwischen imperativer und funktionaler Programmierung
+ /// - Arrays vs. Collections
///
- /// Array mit allen Element-Symbolen
public string[] GetAllSymbols()
{
+ // Klassische Array-Erstellung mit fester Größe
string[] symbols = new string[_elements.Count];
+
+ // Manuelle Population mit for-Schleife (imperativer Stil)
for (int i = 0; i < _elements.Count; i++)
{
symbols[i] = _elements[i].Symbol;
}
+
return symbols;
}
+ // ===== DELEGATION AN HELPER-KLASSEN =====
+
///
- /// Gibt Atomgewichte als Array zurück
+ /// Diese Methoden implementieren das Delegation Pattern
+ ///
+ /// VORTEILE DER DELEGATION:
+ /// - Single Responsibility Principle: Jede Klasse hat einen klaren Zweck
+ /// - Code-Reduktion: Controller wird schlanker und übersichtlicher
+ /// - Testbarkeit: Helper-Klassen können isoliert getestet werden
+ /// - Wartbarkeit: Änderungen an Validierung/Statistik beeinflussen Controller nicht
+ ///
+ /// C# KONZEPTE:
+ /// - Null-Conditional Operator (?.): Verhindert NullReferenceException
+ /// - Null-Coalescing Operator (??): Liefert Fallback-Werte wenn null
+ /// - Lambda Expressions: Kurze Syntax für einfache Delegationen
+ /// - Expression-bodied Members: => Syntax für einzeilige Methoden
+ ///
+ /// FEHLERBEHANDLUNG:
+ /// - Alle Methoden handhaben null-Helper graceful mit Fallback-Werten
+ /// - Keine Exceptions, sondern sichere Default-Werte
///
- /// Array mit allen Atomgewichten
- public double[] GetAtomicWeights()
- {
- double[] weights = new double[_elements.Count];
- for (int i = 0; i < _elements.Count; i++)
- {
- weights[i] = _elements[i].AtomicWeight;
- }
- return weights;
- }
+
+ // ===== VALIDIERUNGS-METHODEN (delegiert an ElementValidator) =====
+
+ ///
+ /// Validiert die gesamte Element-Datenbasis
+ /// Delegation an ElementValidator.ValidateData()
+ /// Fallback: false bei null-Validator
+ ///
+ public bool ValidateData() => _validator?.ValidateData() ?? false;
+
+ ///
+ /// Validiert die Position eines spezifischen Elements im Periodensystem
+ /// Delegation an ElementValidator.ValidateElementPosition()
+ /// Fallback: false bei null-Validator
+ ///
+ public bool ValidateElementPosition(Element? element) => _validator?.ValidateElementPosition(element) ?? false;
+
+ // ===== STATISTIK-METHODEN (delegiert an ElementStatistics) =====
+
+ ///
+ /// Extrahiert alle Atomgewichte als Array
+ /// Delegation an ElementStatistics.GetAtomicWeights()
+ /// Fallback: leeres Array bei null-Statistics
+ ///
+ public double[] GetAtomicWeights() => _statistics?.GetAtomicWeights() ?? new double[0];
+
+ ///
+ /// Berechnet das durchschnittliche Atomgewicht
+ /// Delegation an ElementStatistics.GetAverageAtomicWeight()
+ /// Fallback: 0.0 bei null-Statistics
+ ///
+ public double GetAverageAtomicWeight() => _statistics?.GetAverageAtomicWeight() ?? 0.0;
+
+ ///
+ /// Sammelt alle einzigartigen Element-Serien
+ /// Delegation an ElementStatistics.GetAllSeries()
+ /// Fallback: leere Liste bei null-Statistics
+ ///
+ public List GetAllSeries() => _statistics?.GetAllSeries() ?? new List();
+
+ ///
+ /// Sammelt wichtige Statistiken in einem Tuple
+ /// Tuple Deconstruction: (int, int, double) für strukturierte Daten
+ /// Delegation an ElementStatistics.GetStatistics()
+ /// Fallback: (0, 0, 0.0) bei null-Statistics
+ ///
+ public (int totalElements, int uniqueSeries, double avgWeight) GetStatistics() => _statistics?.GetStatistics() ?? (0, 0, 0.0);
+
+ ///
+ /// Findet das leichteste und schwerste Element
+ /// Tuple mit nullable Elementen: (Element?, Element?)
+ /// Delegation an ElementStatistics.GetWeightExtremes()
+ /// Fallback: (null, null) bei null-Statistics
+ ///
+ public (Element? lightest, Element? heaviest) GetWeightExtremes() => _statistics?.GetWeightExtremes() ?? (null, null);
+
+ ///
+ /// Extrahiert grundlegende Informationen eines Elements
+ /// Tuple mit gemischten Typen: (string, string, double)
+ /// Delegation an ElementStatistics.GetElementInfo()
+ /// Fallback: ("?", "Unknown", 0.0) bei null-Statistics
+ ///
+ public (string symbol, string name, double weight) GetElementInfo(int atomicNumber) => _statistics?.GetElementInfo(atomicNumber) ?? ("?", "Unknown", 0.0);
+
+ ///
+ /// Ermittelt die Position eines Elements im Periodensystem
+ /// Tuple mit Koordinaten: (int row, int column)
+ /// Delegation an ElementStatistics.GetElementPosition()
+ /// Fallback: (-1, -1) für "nicht gefunden" bei null-Statistics
+ ///
+ public (int row, int column) GetElementPosition(int atomicNumber) => _statistics?.GetElementPosition(atomicNumber) ?? (-1, -1);
+ // ===== ELEMENT-SUCHFUNKTIONEN =====
+
///
- /// Berechnet Durchschnittsgewicht aus Array
+ /// Sucht ein Element anhand seiner Ordnungszahl (Atomzahl)
+ ///
+ /// ZWECK:
+ /// - Eindeutige Identifizierung von Elementen
+ /// - Ordnungszahl ist der Primärschlüssel im Periodensystem
+ ///
+ /// C# KONZEPTE:
+ /// - LINQ FirstOrDefault(): Gibt erstes Element oder null zurück
+ /// - Lambda Expression: e => e.AtomicNumber == atomicNumber
+ /// - Nullable Return Type: Element? kann null sein
+ ///
+ /// PARAMETER:
+ /// - atomicNumber: Ordnungszahl des gesuchten Elements (1-118)
+ ///
+ /// RÜCKGABE:
+ /// - Element-Objekt wenn gefunden, null wenn nicht vorhanden
+ ///
+ /// VERWENDUNG:
+ /// var hydrogen = controller.GetElementByAtomicNumber(1);
+ /// if (hydrogen != null) { /* Element verwenden */ }
///
- /// Durchschnittliches Atomgewicht
- public double GetAverageAtomicWeight()
- {
- double[] weights = GetAtomicWeights();
- if (weights.Length == 0) return 0;
-
- double sum = 0;
- for (int i = 0; i < weights.Length; i++)
- {
- sum += weights[i];
- }
- return sum / weights.Length;
- }
-
- ///
- /// Speichert Elemente persistent (NEUE FUNKTION)
- ///
- public void SaveElements()
- {
- try
- {
- DataManager.SaveElements(_elements);
- Logger.Log("Elemente erfolgreich gespeichert");
- }
- catch (Exception ex)
- {
- Logger.LogException(ex, "SaveElements");
- }
- }
-
- ///
- /// Sucht ein Element nach Atomnummer
- ///
- /// Atomnummer des gesuchten Elements
- /// Element oder null wenn nicht gefunden
public Element? GetElementByAtomicNumber(int atomicNumber)
{
- if (atomicNumber <= 0)
- {
- Logger.Log($"Ungültige Atomnummer: {atomicNumber}");
- return null;
- }
-
return _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber);
}
///
- /// Sucht ein Element nach Symbol
+ /// Sucht ein Element anhand seines chemischen Symbols
+ ///
+ /// ZWECK:
+ /// - Benutzerfreundliche Suche mit bekannten Symbolen (H, He, Li, etc.)
+ /// - Case-insensitive Suche für bessere Usability
+ ///
+ /// C# KONZEPTE:
+ /// - String.IsNullOrWhiteSpace(): Robuste Null/Empty-Prüfung
+ /// - StringComparison.OrdinalIgnoreCase: Ignoriert Groß-/Kleinschreibung
+ /// - Early Return Pattern: Frühzeitiger Ausstieg bei ungültigen Eingaben
+ /// - Guard Clauses: Validierung am Methodenstart
+ ///
+ /// PARAMETER:
+ /// - symbol: Chemisches Symbol (z.B. "H", "he", "LI")
+ ///
+ /// RÜCKGABE:
+ /// - Element-Objekt wenn gefunden, null bei ungültigem Symbol oder nicht gefunden
+ ///
+ /// FEHLERBEHANDLUNG:
+ /// - Null/Empty/Whitespace-Eingaben werden sicher behandelt
+ /// - Keine Exception bei ungültigen Eingaben
///
- /// Symbol des gesuchten Elements
- /// Element oder null wenn nicht gefunden
public Element? GetElementBySymbol(string symbol)
{
- if (string.IsNullOrWhiteSpace(symbol))
- {
- Logger.Log("Leeres Symbol übergeben");
- return null;
- }
-
- return _elements.FirstOrDefault(e =>
- string.Equals(e.Symbol, symbol, StringComparison.OrdinalIgnoreCase));
+ // Guard Clause: Ungültige Eingaben frühzeitig abfangen
+ if (string.IsNullOrWhiteSpace(symbol)) return null;
+
+ // Case-insensitive Suche für bessere Benutzerfreundlichkeit
+ return _elements.FirstOrDefault(e => string.Equals(e.Symbol, symbol, StringComparison.OrdinalIgnoreCase));
}
///
- /// Filtert Elemente nach Serie
+ /// Filtert alle Elemente einer bestimmten chemischen Serie
+ ///
+ /// ZWECK:
+ /// - Gruppierung von Elementen nach chemischen Eigenschaften
+ /// - Ermöglicht Analyse von Element-Familien (Metalle, Nichtmetalle, etc.)
+ ///
+ /// C# KONZEPTE:
+ /// - LINQ Where(): Filtert Elemente basierend auf Bedingung
+ /// - ToList(): Konvertiert IEnumerable zu List für weitere Operationen
+ /// - Guard Clause: Schutz vor ungültigen Eingaben
+ ///
+ /// PARAMETER:
+ /// - series: Name der chemischen Serie (z.B. "Alkali metal", "Noble gas")
+ ///
+ /// RÜCKGABE:
+ /// - Liste aller Elemente der angegebenen Serie
+ /// - Leere Liste bei ungültiger Serie oder wenn keine Elemente gefunden
+ ///
+ /// BEISPIEL:
+ /// var alkaliMetals = controller.GetElementsBySeries("Alkali metal");
+ /// // Enthält: Li, Na, K, Rb, Cs, Fr
///
- /// Gewünschte Elementserie
- /// Liste der Elemente der angegebenen Serie
public List GetElementsBySeries(string series)
{
- if (string.IsNullOrWhiteSpace(series))
- {
- return new List();
- }
-
- return _elements.Where(e =>
- string.Equals(e.Series, series, StringComparison.OrdinalIgnoreCase))
- .ToList();
+ // Guard Clause: Ungültige Eingaben behandeln
+ if (string.IsNullOrWhiteSpace(series)) return new List();
+
+ // LINQ-Filterung mit case-insensitive Vergleich
+ return _elements.Where(e => string.Equals(e.Series, series, StringComparison.OrdinalIgnoreCase)).ToList();
}
+ // ===== DATEN-MANAGEMENT =====
+
///
- /// Validiert Grid-Position eines Elements
- ///
- /// Zu validierendes Element
- /// True wenn Position gültig ist
- public bool ValidateElementPosition(Element element)
- {
- if (element == null)
- {
- Logger.Log("Null-Element kann nicht validiert werden");
- return false;
- }
-
- // Periodensystem hat 7 Perioden (0-6) und 18 Gruppen (0-17)
- // Plus Lanthanoid/Actinoid-Reihen bei Zeile 8 und 9
- bool validRow = element.Row >= 0 && element.Row <= 9;
- bool validColumn = element.Column >= 0 && element.Column <= 17;
-
- if (!validRow || !validColumn)
- {
- Logger.Log($"Ungültige Position für {element.Symbol}: ({element.Row},{element.Column})");
- return false;
- }
-
- return true;
- }
-
- ///
- /// Gibt alle verfügbaren Element-Serien zurück
- ///
- /// Liste aller Serien
- public List GetAllSeries()
- {
- return _elements.Select(e => e.Series)
- .Distinct()
- .Where(s => !string.IsNullOrWhiteSpace(s))
- .OrderBy(s => s)
- .ToList();
- }
-
- ///
- /// Überprüft ob alle Elemente korrekt geladen wurden
- ///
- /// True wenn Daten vollständig sind
- public bool ValidateData()
- {
- if (_elements.Count == 0)
- {
- Logger.Log("Keine Elemente geladen");
- return false;
- }
-
- // Überprüfe auf Duplikate bei Atomnummern
- var duplicateNumbers = _elements.GroupBy(e => e.AtomicNumber)
- .Where(g => g.Count() > 1)
- .Select(g => g.Key);
-
- if (duplicateNumbers.Any())
- {
- Logger.Log($"Doppelte Atomnummern gefunden: {string.Join(", ", duplicateNumbers)}");
- return false;
- }
-
- // Überprüfe auf leere Symbole
- var emptySymbols = _elements.Where(e => string.IsNullOrWhiteSpace(e.Symbol));
- if (emptySymbols.Any())
- {
- Logger.Log("Elemente mit leeren Symbolen gefunden");
- return false;
- }
-
- Logger.Log($"Datenvalidierung erfolgreich - {_elements.Count} Elemente validiert");
- return true;
- }
-
- ///
- /// Lädt Daten neu (für Refresh-Funktionalität)
+ /// Lädt alle Elementdaten neu aus dem Persistence-Layer
+ ///
+ /// ZWECK:
+ /// - Aktualisierung bei geänderten Datenquellen
+ /// - Recovery nach Datenfehlern
+ /// - Synchronisation mit externen Datenänderungen
+ ///
+ /// ABLAUF:
+ /// 1. Benutzer über Neuladen informieren
+ /// 2. LoadElements() ruft gesamte Initialisierungslogik auf
+ /// 3. Helper-Klassen werden mit neuen Daten reinitialisiert
+ ///
+ /// VERWENDUNG:
+ /// - Nach Datenimport
+ /// - Bei Corruption Recovery
+ /// - Für Entwicklungs-/Debug-Zwecke
///
public void RefreshData()
{
Logger.Log("Daten werden neu geladen...");
- LoadElements();
+ LoadElements(); // Vollständige Reinitialisierung
}
///
- /// Gibt die Anzahl der geladenen Elemente zurück
+ /// Gibt die aktuelle Anzahl geladener Elemente zurück
+ ///
+ /// ZWECK:
+ /// - Schnelle Verfügbarkeitsprüfung
+ /// - UI-Statusanzeigen
+ /// - Validierung nach Datenoperationen
+ ///
+ /// C# KONZEPT:
+ /// - Expression-bodied Member: => Syntax für einzeilige Properties
+ /// - Count Property: Effiziente Größenabfrage für List<T>
+ ///
+ /// RÜCKGABE:
+ /// - Anzahl der verfügbaren Elemente (0 wenn keine geladen)
///
- /// Anzahl der Elemente
- public int GetElementCount()
- {
- return _elements.Count;
- }
+ public int GetElementCount() => _elements.Count;
- ///
- /// Gibt Element-Position als Tuple zurück
- ///
- /// Atomnummer des Elements
- /// Tuple mit (Row, Column) oder (-1, -1) wenn nicht gefunden
- public (int row, int column) GetElementPosition(int atomicNumber)
- {
- var element = GetElementByAtomicNumber(atomicNumber);
- if (element != null)
- {
- return (element.Row, element.Column);
- }
- return (-1, -1);
- }
-
- ///
- /// Gibt Grundinfos eines Elements als Tuple zurück
- ///
- /// Atomnummer
- /// Tuple mit (Symbol, Name, Gewicht)
- public (string symbol, string name, double weight) GetElementInfo(int atomicNumber)
- {
- var element = GetElementByAtomicNumber(atomicNumber);
- if (element != null)
- {
- return (element.Symbol, element.ElementName, element.AtomicWeight);
- }
- return ("", "Unbekannt", 0.0);
- }
-
- ///
- /// Gibt Statistiken als Tuple zurück
- ///
- /// Tuple mit (Anzahl Elemente, Anzahl Serien, Durchschnittsgewicht)
- public (int totalElements, int uniqueSeries, double avgWeight) GetStatistics()
- {
- var seriesCount = GetAllSeries().Count;
- var avgWeight = GetAverageAtomicWeight();
-
- return (_elements.Count, seriesCount, avgWeight);
- }
-
- ///
- /// Findet leichtestes und schwerstes Element
- ///
- /// Tuple mit (leichtestes Element, schwerstes Element) oder null-Werte wenn keine Elemente
- public (Element? lightest, Element? heaviest) GetWeightExtremes()
- {
- if (!_elements.Any())
- {
- return (null, null);
- }
-
- var lightest = _elements[0];
- var heaviest = _elements[0];
-
- foreach (var element in _elements)
- {
- if (element.AtomicWeight < lightest.AtomicWeight)
- lightest = element;
- if (element.AtomicWeight > heaviest.AtomicWeight)
- heaviest = element;
- }
-
- return (lightest, heaviest);
- }
-
- // ===== NAVIGATION CONTROLLER METHODS (SAUBERES MVC MIT INTERFACE) =====
+ // ===== NAVIGATION CONTROLLER METHODEN =====
///
- /// Behandelt Navigation zum Periodensystem (Controller-Logic)
+ /// Diese Methoden implementieren den Command Pattern für UI-Aktionen
+ ///
+ /// ARCHITEKTUR-PRINZIPIEN:
+ /// - Separation of Concerns: UI-Logik getrennt von Datenlogik
+ /// - Command Pattern: Jede Benutzeraktion wird als Method-Call gekapselt
+ /// - Exception Safety: Alle Navigation-Aktionen sind exception-safe
+ /// - Dependency Injection: NavigationService wird injiziert, nicht direkt instanziiert
+ ///
+ /// C# KONZEPTE:
+ /// - Try-Catch Blocks: Robuste Fehlerbehandlung
+ /// - Null-Conditional Operator (?.): Sichere Methodenaufrufe
+ /// - Method Chaining: navigationService?.Method()
+ /// - Consistent Error Handling: Alle Methoden folgen demselben Pattern
+ ///
+ /// LOGGING:
+ /// - Alle Aktionen werden geloggt für Debugging
+ /// - Exceptions werden mit Kontext geloggt
+ /// - Einheitliche Log-Messages für bessere Nachverfolgung
+ ///
+
+ ///
+ /// Navigiert zur Hauptansicht des Periodensystems
+ ///
+ /// ZWECK:
+ /// - Wechsel zur interaktiven Periodensystem-Darstellung
+ /// - Hauptfunktion der Anwendung
+ ///
+ /// FEHLERBEHANDLUNG:
+ /// - Exception wird geloggt, aber nicht weitergegeben
+ /// - Navigation Service kann null sein (optional dependency)
+ /// - Graceful Degradation bei Navigationsfehlern
///
public void HandleNavigateToPeriodicTable()
{
@@ -371,7 +502,12 @@ namespace Project_Periodensystem.Controller
}
///
- /// Behandelt Navigation zur About-Seite (Controller-Logic)
+ /// Navigiert zur Informationsseite über die Anwendung
+ ///
+ /// ZWECK:
+ /// - Anzeige von Anwendungsinformationen
+ /// - Credits und Versionsinformationen
+ /// - Hilfe und Dokumentation
///
public void HandleNavigateToAbout()
{
@@ -387,7 +523,12 @@ namespace Project_Periodensystem.Controller
}
///
- /// Behandelt Navigation zur Landing Page (Controller-Logic)
+ /// Navigiert zurück zur Startseite/Landing Page
+ ///
+ /// ZWECK:
+ /// - Rückkehr zum Hauptmenü
+ /// - Reset der Anwendung zum Ausgangszustand
+ /// - Home-Button Funktionalität
///
public void HandleNavigateToLanding()
{
@@ -403,7 +544,16 @@ namespace Project_Periodensystem.Controller
}
///
- /// Behandelt Theme-Wechsel (Controller-Logic)
+ /// Wechselt zwischen hellen und dunklen UI-Themes
+ ///
+ /// ZWECK:
+ /// - Benutzerfreundlichkeit durch Theme-Auswahl
+ /// - Accessibility (Dunkel-Modus für Augen-schonend)
+ /// - Moderne UI-Standards erfüllen
+ ///
+ /// UI-PATTERN:
+ /// - Toggle-Funktionalität (Hell ↔ Dunkel)
+ /// - Persistierung des gewählten Themes
///
public void HandleToggleTheme()
{
@@ -419,17 +569,23 @@ namespace Project_Periodensystem.Controller
}
///
- /// Behandelt Daten-Export (Controller-Logic)
+ /// Startet den Datenexport-Prozess
+ ///
+ /// ZWECK:
+ /// - Export der Elementdaten in verschiedene Formate
+ /// - Datensicherung und -portabilität
+ /// - Integration mit anderen Anwendungen
+ ///
+ /// UI-WORKFLOW:
+ /// - Zeigt Bestätigungsdialog an
+ /// - Benutzer wählt Export-Optionen
+ /// - Export wird durchgeführt und bestätigt
///
public void HandleExportData()
{
try
{
Logger.Log("Controller: Daten-Export angefordert");
-
- // Geschäftslogik für Export
- SaveElements(); // Persistierung
-
_navigationService?.ShowExportConfirmation();
}
catch (Exception ex)
diff --git a/Project_Periodensystem.Model/Elements.cs b/Project_Periodensystem.Model/Elements.cs
index b32e2c9..41fb3df 100644
--- a/Project_Periodensystem.Model/Elements.cs
+++ b/Project_Periodensystem.Model/Elements.cs
@@ -1,47 +1,231 @@
-// Definiert einen Namespace – ein Container, um Klassen logisch zu gruppieren.
-// In diesem Fall gehört die Klasse zum "Projekt_periodensystem.Model"-Namespace.
namespace Project_Periodensystem.Model
{
- // Definiert eine öffentliche Klasse namens "Element", die ein chemisches Element repräsentiert.
+ ///
+ /// 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<Element> Collections
+ /// - Sortiert nach AtomicNumber für Periodensystem-Darstellung
+ /// - Gruppiert nach Series für chemische Klassifizierung
+ /// - Positioniert nach Row/Column im UI-Grid
+ ///
public class Element
{
- // Ordnungszahl des Elements (z. B. 1 für Wasserstoff)
+ // ===== IDENTIFIKATIONS-EIGENSCHAFTEN =====
+
+ ///
+ /// 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)
+ ///
public int AtomicNumber { get; set; }
- // Chemisches Symbol des Elements (z. B. "H" für Wasserstoff)
+ ///
+ /// 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)
+ ///
public string Symbol { get; set; }
- // Vollständiger Name des Elements (z. B. "Hydrogen")
+ ///
+ /// 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)
+ /// - "Einsteinium" (nach Albert Einstein)
+ ///
public string ElementName { get; set; }
- // Atommasse (mittlere Masse eines Atoms in u)
+ // ===== PHYSIKALISCHE EIGENSCHAFTEN =====
+
+ ///
+ /// 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
+ ///
public double AtomicWeight { get; set; }
- // Elektronegativität nach Pauling-Skala (z. B. 2.1)
+ ///
+ /// 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)
+ ///
public double Electronegativity { get; set; }
- // Dichte des Elements in g/cm³
+ ///
+ /// 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)
+ ///
public double Density { get; set; }
- // Serie oder Gruppe, zu der das Element gehört (z. B. "Halogen", "Alkalimetall")
+ // ===== KLASSIFIKATIONS-EIGENSCHAFTEN =====
+
+ ///
+ /// 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
+ ///
public string Series { get; set; }
+
+ // ===== POSITIONIERUNGS-EIGENSCHAFTEN =====
+
+ ///
+ /// 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
+ ///
public int Row { get; set; }
+
+ ///
+ /// 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
+ ///
public int Column { get; set; }
- // Konstruktor: Erzeugt ein neues Element-Objekt mit allen relevanten Eigenschaften.
+ // ===== KONSTRUKTOR =====
+
+ ///
+ /// 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);
+ ///
public Element(int atomicNumber, string symbol, string elementname, double atomicWeight,
double electronegativity, double density, string series, int row, int column)
{
- // Weist den Eigenschaften beim Erzeugen eines Objekts die übergebenen Werte zu
- AtomicNumber = atomicNumber;
- Symbol = symbol;
- ElementName = elementname;
- AtomicWeight = atomicWeight;
- Electronegativity = electronegativity;
- Density = density;
- Series = series;
- Row = row;
- Column = 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
}
}
}
diff --git a/Project_Periodensystem.Model/Logger.cs b/Project_Periodensystem.Model/Logger.cs
index 06de07a..4795d0e 100644
--- a/Project_Periodensystem.Model/Logger.cs
+++ b/Project_Periodensystem.Model/Logger.cs
@@ -5,16 +5,68 @@ using System.Linq;
namespace Project_Periodensystem.Model
{
///
- /// Einfacher Logger für Debug-Ausgaben und Fehlerprotokollierung
+ /// Zentrale Logging-Klasse für Debug-Ausgaben und Fehlerprotokollierung
+ ///
+ /// ZWECK UND ARCHITEKTUR:
+ /// - Einheitliche Logging-Infrastruktur für die gesamte Anwendung
+ /// - Dual-Output: Konsole (Development) und Datei (Production/Debugging)
+ /// - Verschiedene Log-Level für strukturierte Protokollierung
+ /// - Demonstration verschiedener C#-Konzepte und Datentypen
+ ///
+ /// DESIGN PATTERNS:
+ /// - Static Class: Globaler Zugriff ohne Instanziierung
+ /// - Facade Pattern: Vereinfachte API für komplexe Logging-Operationen
+ /// - Strategy Pattern: Verschiedene Ausgabekanäle (Konsole, Datei)
+ ///
+ /// C# KONZEPTE:
+ /// - Static Constructor: Einmalige Initialisierung beim ersten Zugriff
+ /// - Exception Handling: Try-Catch für robuste Datei-Operationen
+ /// - Method Overloading: Verschiedene LogArray-Varianten
+ /// - Conditional Compilation: [Conditional("DEBUG")] für LogDebug
+ /// - LINQ: Select() für Datenformatierung
+ /// - String Interpolation: $"Text {variable}" für lesbare Ausgaben
+ ///
+ /// SICHERHEIT UND ROBUSTHEIT:
+ /// - Alle Datei-Operationen sind exception-safe
+ /// - Logging-Fehler bringen die Hauptanwendung nicht zum Absturz
+ /// - Graceful Degradation bei fehlenden Dateiberechtigungen
///
public static class Logger
{
+ ///
+ /// Pfad zur Log-Datei im lokalen Anwendungsverzeichnis
+ ///
+ /// PFAD-KONSTRUKTION:
+ /// - Environment.SpecialFolder.LocalApplicationData: Benutzer-spezifischer App-Ordner
+ /// - Windows: C:\Users\[Username]\AppData\Local\Periodensystem\app.log
+ /// - Cross-Platform: Funktioniert auf Windows, Linux, macOS
+ ///
+ /// C# KONZEPTE:
+ /// - Path.Combine(): Sichere Pfad-Konstruktion (OS-unabhängig)
+ /// - Environment.SpecialFolder: Standard-Verzeichnisse des Betriebssystems
+ /// - Readonly Field: Kann nur bei Deklaration oder im static Constructor gesetzt werden
+ ///
private static readonly string LogFilePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Periodensystem", "app.log");
///
- /// Statischer Initializer - erstellt Log-Verzeichnis
+ /// Statischer Konstruktor - Einmalige Initialisierung der Logger-Infrastruktur
+ ///
+ /// ZWECK:
+ /// - Erstellt das Log-Verzeichnis falls es nicht existiert
+ /// - Wird automatisch beim ersten Zugriff auf die Klasse aufgerufen
+ /// - Kann nicht explizit aufgerufen werden
+ ///
+ /// C# KONZEPTE:
+ /// - Static Constructor: Automatische Initialisierung ohne Parameter
+ /// - Path.GetDirectoryName(): Extrahiert Verzeichnis aus vollständigem Pfad
+ /// - Directory.CreateDirectory(): Erstellt Verzeichnis-Hierarchie rekursiv
+ /// - Exception Handling: Fehler werden "geschluckt" für Robustheit
+ ///
+ /// FEHLERBEHANDLUNG:
+ /// - Bei Problemen wird nur Konsolen-Logging verwendet
+ /// - Keine Exception nach außen, da Logging optional ist
///
static Logger()
{
@@ -29,25 +81,52 @@ namespace Project_Periodensystem.Model
catch
{
// Falls Log-Datei nicht erstellt werden kann, nur Konsole verwenden
+ // Graceful Degradation: Hauptfunktionalität nicht beeinträchtigen
}
}
+ // ===== HAUPTPROTOKOLLIERUNGS-METHODEN =====
+
///
- /// Protokolliert eine Nachricht sowohl in Konsole als auch Datei
+ /// Zentrale Logging-Methode - protokolliert Nachrichten dual (Konsole + Datei)
+ ///
+ /// ZWECK:
+ /// - Universelle Protokollierung für alle Anwendungsereignisse
+ /// - Entwickler sehen Ausgaben in Konsole (sofortiges Feedback)
+ /// - Benutzer/Support kann Logs aus Datei analysieren
+ ///
+ /// C# KONZEPTE:
+ /// - String.IsNullOrWhiteSpace(): Robuste Null/Empty/Whitespace-Prüfung
+ /// - DateTime.Now.ToString(): Formatierte Zeitstempel
+ /// - String Interpolation: $"[{timestamp}] {message}"
+ /// - File.AppendAllText(): Atomare Datei-Operation
+ /// - Environment.NewLine: OS-spezifische Zeilentrenner
+ ///
+ /// FEHLERBEHANDLUNG:
+ /// - Guard Clause: Leere Nachrichten werden ignoriert
+ /// - Try-Catch um Datei-Operation: Konsole funktioniert immer
+ /// - Keine Exception nach außen: Logging darf nie Hauptanwendung stören
+ ///
+ /// THREAD-SAFETY:
+ /// - File.AppendAllText ist thread-safe
+ /// - Console.WriteLine ist thread-safe
+ /// - Methode kann von mehreren Threads gleichzeitig aufgerufen werden
///
- /// Zu protokollierende Nachricht
+ /// Zu protokollierende Nachricht (wird validiert)
public static void Log(string message)
{
+ // Guard Clause: Ungültige Eingaben frühzeitig abfangen
if (string.IsNullOrWhiteSpace(message))
return;
+ // Zeitstempel im ISO-ähnlichen Format für bessere Lesbarkeit
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var logEntry = $"[{timestamp}] {message}";
- // Konsolen-Ausgabe (für Debug)
+ // Konsolen-Ausgabe (für Entwicklung und sofortiges Feedback)
Console.WriteLine(logEntry);
- // Datei-Ausgabe (für Persistenz)
+ // Datei-Ausgabe (für Persistenz und spätere Analyse)
try
{
File.AppendAllText(LogFilePath, logEntry + Environment.NewLine);
@@ -55,22 +134,46 @@ namespace Project_Periodensystem.Model
catch
{
// Fehler beim Schreiben ignorieren um App nicht zum Absturz zu bringen
+ // Silent Fail: Logging ist nice-to-have, nicht essential
}
}
+ // ===== SPEZIALISIERTE LOGGING-METHODEN =====
+
///
- /// Protokolliert eine Exception mit Stack-Trace
+ /// Protokolliert Exceptions mit vollständigen Diagnose-Informationen
+ ///
+ /// ZWECK:
+ /// - Strukturierte Fehlerprotokollierung für Debugging
+ /// - Vollständige Stack-Trace-Information für Fehleranalyse
+ /// - Kontextuelle Information für bessere Problemlösung
+ ///
+ /// C# KONZEPTE:
+ /// - Exception Handling: ex.Message und ex.StackTrace Properties
+ /// - Null-Check: Schutz vor null-Exceptions
+ /// - String Interpolation: Eingebettete Variablen in Strings
+ /// - Conditional Operator: condition ? valueIfTrue : valueIfFalse
+ /// - Multi-Line Strings: \n für Zeilenumbrüche
+ ///
+ /// PARAMETER:
+ /// - ex: Die zu protokollierende Exception (kann theoretisch null sein)
+ /// - context: Optional - zusätzlicher Kontext (Methodenname, Operation, etc.)
+ ///
+ /// VERWENDUNG:
+ /// try { riskyOperation(); } catch (Exception ex) { Logger.LogException(ex, "DataLoad"); }
///
/// Exception die protokolliert werden soll
- /// Zusätzlicher Kontext
+ /// Zusätzlicher Kontext (Methodenname, Operation, etc.)
public static void LogException(Exception ex, string context = "")
{
+ // Null-Schutz: Auch ungültige Exception-Objekte handhaben
if (ex == null)
{
- Log("Null-Exception übergeben");
+ Log("Null-Exception übergeben - möglicher Programmierfehler");
return;
}
+ // Formatierung je nach verfügbarem Kontext
var message = string.IsNullOrWhiteSpace(context)
? $"EXCEPTION: {ex.Message}\nStack: {ex.StackTrace}"
: $"EXCEPTION in {context}: {ex.Message}\nStack: {ex.StackTrace}";
@@ -79,35 +182,87 @@ namespace Project_Periodensystem.Model
}
///
- /// Protokolliert eine Warnung
+ /// Protokolliert Warnungen - für nicht-kritische Probleme
+ ///
+ /// ZWECK:
+ /// - Kennzeichnung von Problemen die behoben werden sollten
+ /// - Unterscheidung von Informationen und echten Fehlern
+ /// - Monitoring von potentiellen Problemen
+ ///
+ /// BEISPIELE:
+ /// - Veraltete API-Aufrufe
+ /// - Performance-Probleme
+ /// - Unerwartete aber handhabbare Situationen
///
- /// Warnung
+ /// Warnung (wird mit WARNING: Präfix versehen)
public static void LogWarning(string message)
{
Log($"WARNING: {message}");
}
///
- /// Protokolliert einen Fehler
+ /// Protokolliert Fehler - für schwerwiegende Probleme
+ ///
+ /// ZWECK:
+ /// - Kennzeichnung von Fehlern die Funktionalität beeinträchtigen
+ /// - Höhere Priorität als Warnings bei Log-Analyse
+ /// - Monitoring von kritischen Problemen
+ ///
+ /// BEISPIELE:
+ /// - Datenverlust oder Corruption
+ /// - Netzwerk-/Datenbankfehler
+ /// - Konfigurationsprobleme
///
- /// Fehlermeldung
+ /// Fehlermeldung (wird mit ERROR: Präfix versehen)
public static void LogError(string message)
{
Log($"ERROR: {message}");
}
///
- /// Protokolliert Debug-Informationen (nur in Debug-Build)
+ /// Protokolliert Debug-Informationen - nur in Debug-Builds kompiliert
+ ///
+ /// ZWECK:
+ /// - Detaillierte Entwicklungs-Informationen
+ /// - Automatische Entfernung in Release-Builds
+ /// - Performance-Optimierung (keine Debug-Logs in Production)
+ ///
+ /// C# KONZEPTE:
+ /// - Conditional Compilation: [Conditional("DEBUG")]
+ /// - Attribute-based Programming: Verhalten durch Metadaten steuern
+ /// - Build Configuration: Unterschiedliches Verhalten je nach Build-Typ
+ ///
+ /// COMPILER-VERHALTEN:
+ /// - Debug Build: Methode wird normal ausgeführt
+ /// - Release Build: Methoden-Aufrufe werden vollständig entfernt
+ /// - Zero Performance Impact in Production
///
- /// Debug-Nachricht
+ /// Debug-Nachricht (wird mit DEBUG: Präfix versehen)
[System.Diagnostics.Conditional("DEBUG")]
public static void LogDebug(string message)
{
Log($"DEBUG: {message}");
}
+ // ===== DATEI-MANAGEMENT UND UTILITY-METHODEN =====
+
///
- /// Löscht die Log-Datei (für Cleanup)
+ /// Löscht die Log-Datei für Cleanup-Operationen
+ ///
+ /// ZWECK:
+ /// - Speicherplatz freigeben bei großen Log-Dateien
+ /// - Fresh Start für neue Test-Sessions
+ /// - Maintenance-Operation für Anwendungs-Lifecycle
+ ///
+ /// C# KONZEPTE:
+ /// - File.Exists(): Existenz-Prüfung vor Operation
+ /// - File.Delete(): Atomare Datei-Löschung
+ /// - Exception Handling: Robust gegen Berechtigungsprobleme
+ ///
+ /// SICHERHEIT:
+ /// - Prüft Existenz vor Löschung (vermeidet FileNotFoundException)
+ /// - Catch für Berechtigungsfehler oder Datei-in-Verwendung
+ /// - Loggt eigene Operationen (self-documenting)
///
public static void ClearLog()
{
@@ -116,7 +271,7 @@ namespace Project_Periodensystem.Model
if (File.Exists(LogFilePath))
{
File.Delete(LogFilePath);
- Log("Log-Datei gelöscht");
+ Log("Log-Datei gelöscht und neu initialisiert");
}
}
catch (Exception ex)
@@ -126,40 +281,97 @@ namespace Project_Periodensystem.Model
}
///
- /// Gibt den Pfad zur Log-Datei zurück
+ /// Gibt den vollständigen Pfad zur Log-Datei zurück
+ ///
+ /// ZWECK:
+ /// - Ermöglicht externen Tools Zugriff auf Log-Datei
+ /// - Debugging: Entwickler kann Log-Datei manuell öffnen
+ /// - Integration: Andere Komponenten können Logs lesen
+ ///
+ /// KAPSELUNG:
+ /// - Kontrollierter Zugriff auf private LogFilePath
+ /// - Readonly-Zugriff: Externe Komponenten können Pfad nicht ändern
+ /// - Information Hiding: Implementation Details bleiben verborgen
///
- /// Vollständiger Pfad zur Log-Datei
+ /// Vollständiger Pfad zur Log-Datei (absoluter Pfad)
public static string GetLogFilePath()
{
return LogFilePath;
}
+ // ===== SPEZIALISIERTE DATENTYP-LOGGING (C# LERNZWECK) =====
+
///
- /// Loggt ein Array von Strings
+ /// Loggt String-Arrays - demonstriert Array-Verarbeitung
+ ///
+ /// ZWECK:
+ /// - Zeigt Array-Inhalte in lesbarer Form
+ /// - Demonstriert string.Join() für Array-zu-String-Konvertierung
+ /// - Nützlich für Listen von Elementsymbolen, Namen, etc.
+ ///
+ /// C# KONZEPTE:
+ /// - Method Overloading: Mehrere LogArray-Methoden für verschiedene Typen
+ /// - string.Join(): Elegante Array-zu-String-Konvertierung
+ /// - Array-Parameter: string[] als Eingabe
+ ///
+ /// BEISPIEL-AUSGABE:
+ /// "Element-Symbole: [H, He, Li, Be, B, C, N, O, F, Ne]"
///
- /// Titel für das Array
- /// Array von Items
+ /// Beschreibender Titel für das Array
+ /// Array von Strings zur Anzeige
public static void LogArray(string title, string[] items)
{
Log($"{title}: [{string.Join(", ", items)}]");
}
///
- /// Loggt ein Array von Zahlen
+ /// Loggt Double-Arrays - demonstriert numerische Array-Verarbeitung
+ ///
+ /// ZWECK:
+ /// - Zeigt numerische Daten in formatierter Form
+ /// - Demonstriert LINQ Select() für Datenformatierung
+ /// - Nützlich für Atomgewichte, Dichten, Elektronegativitäten
+ ///
+ /// C# KONZEPTE:
+ /// - LINQ Select(): Funktionale Programmierung für Datentransformation
+ /// - Lambda Expression: n => n.ToString("F2") für Formatierung
+ /// - ToString() mit Format-String: "F2" für 2 Dezimalstellen
+ /// - Method Overloading: Verschiedene Typen, gleicher Methodenname
+ ///
+ /// BEISPIEL-AUSGABE:
+ /// "Atomgewichte: [1.01, 4.00, 6.94, 9.01, 10.81]"
///
- /// Titel für das Array
- /// Array von Zahlen
+ /// Beschreibender Titel für das Array
+ /// Array von Double-Werten zur Anzeige
public static void LogArray(string title, double[] numbers)
{
+ // LINQ Select() wandelt jede Zahl in formatierten String um
var formattedNumbers = numbers.Select(n => n.ToString("F2")).ToArray();
Log($"{title}: [{string.Join(", ", formattedNumbers)}]");
}
///
- /// Loggt Tuple-Informationen
+ /// Loggt Tuple-Informationen - demonstriert strukturierte Datenausgabe
+ ///
+ /// ZWECK:
+ /// - Zeigt Tuple-Inhalte in lesbarer Form
+ /// - Demonstriert strukturierte Datenprotokollierung
+ /// - Nützlich für Element-Statistiken und zusammengehörige Werte
+ ///
+ /// C# KONZEPTE:
+ /// - Tuple: Strukturierte Datencontainer
+ /// - String als Parameter: Bereits formatierte Tuple-Darstellung
+ /// - Delegation: Ruft zentrale Log()-Methode auf
+ ///
+ /// VERWENDUNG:
+ /// var stats = GetStatistics(); // returns (int, int, double)
+ /// Logger.LogTuple("Statistiken", $"Elemente: {stats.Item1}, Serien: {stats.Item2}");
+ ///
+ /// BEISPIEL-AUSGABE:
+ /// "Element-Info: Symbol: H, Name: Hydrogen, Gewicht: 1.01"
///
- /// Titel
- /// Tuple als string
+ /// Beschreibender Titel für das Tuple
+ /// Bereits formatierte Tuple-Darstellung als String
public static void LogTuple(string title, string tupleInfo)
{
Log($"{title}: {tupleInfo}");
diff --git a/Project_Periodensystem.Persistence/DataManager.cs b/Project_Periodensystem.Persistence/DataManager.cs
index 0203550..57c002a 100644
--- a/Project_Periodensystem.Persistence/DataManager.cs
+++ b/Project_Periodensystem.Persistence/DataManager.cs
@@ -7,83 +7,233 @@ using Project_Periodensystem.Model;
namespace Project_Periodensystem.Persistence
{
///
- /// Erweiterte Persistenz - Speichern/Laden von JSON-Dateien
+ /// Zentrale Persistenz-Schicht für JSON-basierte Datenspeicherung
+ ///
+ /// ZWECK UND ARCHITEKTUR:
+ /// - Abstrahiert Datei-I/O von der Geschäftslogik (Separation of Concerns)
+ /// - Implementiert Repository Pattern für Element- und Settings-Daten
+ /// - Bietet Fallback-Mechanismus für robuste Datenversorgung
+ /// - Demonstriert moderne .NET JSON-Serialisierung
+ ///
+ /// DESIGN PATTERNS:
+ /// - Repository Pattern: Zentrale Datenquelle mit einheitlicher API
+ /// - Static Class: Globaler Zugriff ohne Instanziierung
+ /// - Fallback Strategy: Graceful Degradation bei fehlenden Dateien
+ /// - Factory Pattern: Erstellt Default-Objekte wenn nötig
+ ///
+ /// C# KONZEPTE:
+ /// - System.Text.Json: Modernes JSON-Framework (.NET Core/5+)
+ /// - JsonSerializerOptions: Konfiguration der JSON-Ausgabe
+ /// - Generic Methods: Wiederverwendbare Serialisierung für verschiedene Typen
+ /// - Exception Handling: Robuste Fehlerbehandlung bei I/O-Operationen
+ /// - Null-Coalescing (??): Fallback-Werte bei null-Objekten
+ ///
+ /// DATENSPEICHERUNG:
+ /// - LocalApplicationData: Benutzer-spezifische, nicht-roaming Daten
+ /// - JSON Format: Menschenlesbar, plattformunabhängig, einfach zu debuggen
+ /// - Strukturierte Verzeichnisse: Organisierte Dateiablage
///
public static class DataManager
{
+ // ===== PFAD-KONFIGURATION =====
+
+ ///
+ /// Basis-Verzeichnis für alle Anwendungsdaten
+ ///
+ /// PFAD-STRATEGIEN:
+ /// - LocalApplicationData: Benutzer-spezifisch, lokal (nicht synchronisiert)
+ /// - Windows: C:\Users\[Username]\AppData\Local\Periodensystem\
+ /// - Cross-Platform: Funktioniert auf Windows, Linux, macOS
+ ///
+ /// VORTEILE:
+ /// - Keine Admin-Rechte erforderlich
+ /// - Benutzer-spezifische Isolation
+ /// - Standard-Konformität mit OS-Richtlinien
+ ///
private static readonly string DataDirectory = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Periodensystem");
+ ///
+ /// Vollständiger Pfad zur Element-Datenbasis (JSON)
+ /// Speichert alle chemischen Elemente mit ihren Eigenschaften
+ ///
private static readonly string ElementsFile = Path.Combine(DataDirectory, "elements.json");
+
+ ///
+ /// Vollständiger Pfad zu Benutzereinstellungen (JSON)
+ /// Speichert Präferenzen wie Theme, Sprache, letzte Nutzung
+ ///
private static readonly string SettingsFile = Path.Combine(DataDirectory, "settings.json");
+ // ===== ELEMENT-DATEN PERSISTENZ =====
+
///
- /// Speichert Elemente als JSON
+ /// Speichert eine Element-Liste als JSON-Datei
+ ///
+ /// ZWECK:
+ /// - Persistierung von benutzerdefinierten oder bearbeiteten Elementen
+ /// - Backup von Element-Daten für Wiederherstellung
+ /// - Export-Funktionalität für Datenübertragung
+ ///
+ /// C# KONZEPTE:
+ /// - JsonSerializer.Serialize(): Moderne .NET JSON-Serialisierung
+ /// - JsonSerializerOptions: Konfiguration der JSON-Ausgabe
+ /// - WriteIndented: Menschenlesbare Formatierung (Pretty-Print)
+ /// - Directory.CreateDirectory(): Erstellt Verzeichnis-Hierarchie falls nötig
+ /// - File.WriteAllText(): Atomare Datei-Schreiboperation
+ ///
+ /// FEHLERBEHANDLUNG:
+ /// - Try-Catch um gesamte Operation
+ /// - Logging aller Erfolgs- und Fehlerfälle
+ /// - Graceful Degradation: Anwendung funktioniert ohne Persistenz
+ ///
+ /// JSON-AUSGABE:
+ /// - Eingerückt und formatiert für manuelle Bearbeitung
+ /// - UTF-8 Encoding für internationale Zeichen
+ /// - Standard JSON-Format für Interoperabilität
///
+ /// Liste der zu speichernden Elemente
public static void SaveElements(List elements)
{
try
{
+ // Verzeichnis erstellen falls nicht vorhanden
Directory.CreateDirectory(DataDirectory);
+
+ // JSON-Serialisierung mit lesbarer Formatierung
var json = JsonSerializer.Serialize(elements, new JsonSerializerOptions { WriteIndented = true });
+
+ // Atomare Datei-Operation (ersetzt bestehende Datei)
File.WriteAllText(ElementsFile, json);
- Logger.Log($"Elemente gespeichert: {elements.Count} Einträge");
+
+ Logger.Log($"Elemente erfolgreich gespeichert: {elements.Count} Einträge in {ElementsFile}");
}
catch (Exception ex)
{
Logger.LogException(ex, "SaveElements");
+ // Keine Weiterleitung der Exception - Speichern ist optional
}
}
///
- /// Lädt Elemente aus JSON oder Fallback zu eingebauten Daten
+ /// Lädt Elemente aus JSON-Datei mit Fallback zu eingebauten Daten
+ ///
+ /// ZWECK:
+ /// - Primäre Datenquelle für alle Element-Informationen
+ /// - Robuste Datenversorgung durch Fallback-Mechanismus
+ /// - Unterstützung für persistierte Benutzeränderungen
+ ///
+ /// FALLBACK-STRATEGIE:
+ /// 1. Versuche JSON-Datei zu laden (benutzerdefinierte Daten)
+ /// 2. Bei Fehlern: Fallback zu PeriodicTableData.Elements (eingebaute Daten)
+ /// 3. Garantiert immer eine funktionsfähige Element-Liste
+ ///
+ /// C# KONZEPTE:
+ /// - JsonSerializer.Deserialize<T>(): Generische Deserialisierung
+ /// - File.Exists(): Existenz-Prüfung vor Dateizugriff
+ /// - Null-Conditional Check: elements != null && elements.Count > 0
+ /// - Multiple Return Points: Verschiedene Ausstiegspunkte je nach Szenario
+ ///
+ /// FEHLERBEHANDLUNG:
+ /// - Alle I/O-Operationen in try-catch
+ /// - Validierung der deserialisierten Daten
+ /// - Logging aller Ladeschritte für Debugging
+ /// - Graceful Fallback ohne Exception-Weiterleitung
///
+ /// Liste aller verfügbaren chemischen Elemente
public static List LoadElements()
{
try
{
+ // Prüfung ob benutzerdefinierte Daten existieren
if (File.Exists(ElementsFile))
{
var json = File.ReadAllText(ElementsFile);
var elements = JsonSerializer.Deserialize>(json);
+
+ // Validierung der deserialisierten Daten
if (elements != null && elements.Count > 0)
{
- Logger.Log($"Elemente aus Datei geladen: {elements.Count}");
+ Logger.Log($"Elemente aus benutzerdefinierter Datei geladen: {elements.Count} Einträge");
return elements;
}
}
}
catch (Exception ex)
{
- Logger.LogException(ex, "LoadElements");
+ Logger.LogException(ex, "LoadElements - JSON Loading");
+ // Kein Re-throw - Fallback folgt
}
- // Fallback zu eingebauten Daten
- Logger.Log("Fallback zu eingebauten Element-Daten");
+ // Fallback zu eingebauten, statischen Daten
+ Logger.Log("Fallback zu eingebauten Element-Daten (PeriodicTableData)");
return PeriodicTableData.Elements;
}
+ // ===== BENUTZEREINSTELLUNGEN PERSISTENZ =====
+
///
- /// Speichert Benutzereinstellungen
+ /// Speichert Benutzereinstellungen als JSON-Datei
+ ///
+ /// ZWECK:
+ /// - Persistierung von Benutzer-Präferenzen zwischen App-Sessions
+ /// - Theme-Einstellungen, Sprach-Präferenzen, etc. speichern
+ /// - Personalisierte Benutzererfahrung ermöglichen
+ ///
+ /// C# KONZEPTE:
+ /// - Gleiche JSON-Serialisierung wie bei Elementen
+ /// - Konsistente Fehlerbehandlung und Logging
+ /// - Atomare Datei-Operationen für Datenintegrität
+ ///
+ /// SETTINGS-BEISPIELE:
+ /// - UI Theme (Light/Dark)
+ /// - Bevorzugte Sprache
+ /// - Letzte Nutzung (für Statistiken)
+ /// - Personalisierte Element-Ansichten
///
+ /// AppSettings-Objekt mit Benutzer-Präferenzen
public static void SaveSettings(AppSettings settings)
{
try
{
+ // Verzeichnis sicherstellen (gleich wie bei Elementen)
Directory.CreateDirectory(DataDirectory);
+
+ // JSON-Serialisierung mit Pretty-Print
var json = JsonSerializer.Serialize(settings, new JsonSerializerOptions { WriteIndented = true });
+
+ // Atomare Speicherung
File.WriteAllText(SettingsFile, json);
+
+ Logger.Log($"Benutzereinstellungen gespeichert: Theme={settings.LastTheme}, Sprache={settings.PreferredLanguage}");
}
catch (Exception ex)
{
Logger.LogException(ex, "SaveSettings");
+ // Keine Exception-Weiterleitung - Settings sind optional
}
}
///
- /// Lädt Benutzereinstellungen
+ /// Lädt Benutzereinstellungen aus JSON-Datei
+ ///
+ /// ZWECK:
+ /// - Wiederherstellung der Benutzer-Präferenzen beim App-Start
+ /// - Fallback zu Default-Settings bei fehlender oder korrupter Datei
+ /// - Konsistente Benutzererfahrung über Sessions hinweg
+ ///
+ /// FALLBACK-VERHALTEN:
+ /// - Bei fehlender Datei: Neue AppSettings() mit Defaults
+ /// - Bei JSON-Fehlern: Neue AppSettings() mit Defaults
+ /// - Garantiert immer gültige Settings-Objekt
+ ///
+ /// C# KONZEPTE:
+ /// - Null-Coalescing Operator (??): settings ?? new AppSettings()
+ /// - Constructor mit Default-Werten in AppSettings
+ /// - Robuste Deserialisierung mit Fallback
///
+ /// AppSettings-Objekt (entweder geladen oder mit Defaults)
public static AppSettings LoadSettings()
{
try
@@ -92,25 +242,87 @@ namespace Project_Periodensystem.Persistence
{
var json = File.ReadAllText(SettingsFile);
var settings = JsonSerializer.Deserialize(json);
- return settings ?? new AppSettings();
+
+ // Null-Coalescing für sichere Rückgabe
+ var result = settings ?? new AppSettings();
+ Logger.Log($"Benutzereinstellungen geladen: Theme={result.LastTheme}");
+ return result;
}
}
catch (Exception ex)
{
Logger.LogException(ex, "LoadSettings");
+ // Kein Re-throw - Fallback zu Defaults
}
+ // Fallback zu Default-Settings
+ Logger.Log("Fallback zu Standard-Benutzereinstellungen");
return new AppSettings();
}
}
///
- /// Benutzereinstellungen für Persistenz
+ /// Datenmodell für persistierte Benutzereinstellungen
+ ///
+ /// ZWECK UND STRUKTUR:
+ /// - Kapselt alle persistierbaren Benutzer-Präferenzen
+ /// - Einfache Erweiterung um neue Settings möglich
+ /// - JSON-serialisierbar durch Auto-Properties
+ /// - Default-Werte für robuste Initialisierung
+ ///
+ /// DESIGN PRINCIPLES:
+ /// - Data Transfer Object (DTO): Reine Datenklasse
+ /// - Default Values: Sinnvolle Startwerte für neue Installationen
+ /// - Extensibility: Einfache Erweiterung um neue Properties
+ /// - Immutable nach Konstruktion: Properties könnten readonly sein
+ ///
+ /// C# KONZEPTE:
+ /// - Auto-Properties mit Default-Initialisierung
+ /// - DateTime für Zeitstempel
+ /// - String-Properties für einfache Serialisierung
+ /// - Parameterloser Constructor (implizit für JSON-Deserialisierung)
+ ///
+ /// JSON-SERIALISIERUNG:
+ /// - Alle Properties werden automatisch serialisiert
+ /// - Property-Namen werden als JSON-Keys verwendet
+ /// - Default-Werte sorgen für robuste Deserialisierung
///
public class AppSettings
{
+ ///
+ /// Zuletzt verwendetes UI-Theme
+ ///
+ /// WERTE:
+ /// - "Light": Helles Theme für Tag-Nutzung
+ /// - "Dark": Dunkles Theme für augen-schonende Nutzung
+ /// - "Auto": System-Theme folgen (Windows/macOS)
+ ///
+ /// DEFAULT: "Dark" - Moderner Standard für Entwicklungs-Tools
+ ///
public string LastTheme { get; set; } = "Dark";
+
+ ///
+ /// Zeitstempel der letzten Anwendungsnutzung
+ ///
+ /// ZWECK:
+ /// - Nutzungsstatistiken
+ /// - "Willkommen zurück"-Funktionen
+ /// - Data Analytics für Verbesserungen
+ ///
+ /// DEFAULT: DateTime.Now - Aktueller Zeitpunkt bei Erstellung
+ ///
public DateTime LastUsed { get; set; } = DateTime.Now;
+
+ ///
+ /// Bevorzugte Sprache der Benutzeroberfläche
+ ///
+ /// WERTE:
+ /// - "German": Deutsche Lokalisierung
+ /// - "English": Englische Lokalisierung
+ /// - "French": Französische Lokalisierung (wenn implementiert)
+ ///
+ /// DEFAULT: "German" - Da es ein deutsches Lernprojekt ist
+ ///
public string PreferredLanguage { get; set; } = "German";
}
}
\ No newline at end of file
diff --git a/Project_Periodensystem.Persistence/PeriodicTableData.cs b/Project_Periodensystem.Persistence/PeriodicTableData.cs
index f3413c5..ff40ff7 100644
--- a/Project_Periodensystem.Persistence/PeriodicTableData.cs
+++ b/Project_Periodensystem.Persistence/PeriodicTableData.cs
@@ -3,31 +3,99 @@ using Project_Periodensystem.Model;
namespace Project_Periodensystem.Persistence
{
+ ///
+ /// Statische Datenquelle für alle chemischen Elemente des Periodensystems
+ ///
+ /// ZWECK UND DATENMODELL:
+ /// - Eingebaute, unveränderliche Datenbasis für das Periodensystem
+ /// - Fallback-Datenquelle wenn externe JSON-Dateien nicht verfügbar sind
+ /// - Demonstration großer statischer Datenstrukturen in C#
+ /// - Vollständige wissenschaftliche Elementdaten für Bildungszwecke
+ ///
+ /// DATENORGANISATION:
+ /// - 118 chemische Elemente (vollständiges Periodensystem bis 2023)
+ /// - Organisiert nach Perioden (Zeilen) für bessere Lesbarkeit
+ /// - Jedes Element mit 9 Eigenschaften (AtomicNumber bis Column)
+ /// - Wissenschaftlich korrekte Daten basierend auf IUPAC-Standards
+ ///
+ /// C# KONZEPTE:
+ /// - Static Class: Globaler Zugriff ohne Instanziierung
+ /// - Static Property: Elements als unveränderliche Datenquelle
+ /// - Collection Initializer: new List<Element> { ... } Syntax
+ /// - Object Initializer: new Element(...) für jeden Eintrag
+ /// - Large Data Arrays: Umgang mit umfangreichen Datensätzen
+ ///
+ /// DESIGN PATTERNS:
+ /// - Static Factory: Stellt vorgefertigte Element-Sammlung bereit
+ /// - Immutable Data: Nur Getter, keine Setter für Elements
+ /// - Reference Data: Unveränderliche Stammdaten
+ /// - Embedded Resource: Daten sind Teil der kompilierten Assembly
+ ///
+ /// WISSENSCHAFTLICHE GENAUIGKEIT:
+ /// - Atomgewichte: Relative Atommassen basierend auf IUPAC 2021
+ /// - Elektronegativität: Pauling-Skala mit 2 Dezimalstellen
+ /// - Dichte: g/cm³ bei Standardbedingungen (20°C, 1 atm)
+ /// - Elementserien: Moderne Klassifikation nach chemischen Eigenschaften
+ /// - Positionen: Row/Column entsprechen Standard-Periodensystem-Layout
+ ///
+ /// WARTUNG UND ERWEITERUNG:
+ /// - Neue Elemente können einfach zur Liste hinzugefügt werden
+ /// - Datenformat ist konsistent und selbst-dokumentierend
+ /// - Kommentare gruppieren Elemente nach Perioden für Übersichtlichkeit
+ /// - Jeder Eintrag folgt dem gleichen Schema für Konsistenz
+ ///
public static class PeriodicTableData
{
+ ///
+ /// Vollständige Liste aller bekannten chemischen Elemente
+ ///
+ /// DATENSTRUKTUR:
+ /// - List<Element>: Dynamische Sammlung von Element-Objekten
+ /// - Static Property: Einmalige Initialisierung beim ersten Zugriff
+ /// - Read-Only: Nur Getter, keine externe Manipulation möglich
+ /// - Auto-Property: Compiler generiert backing field automatisch
+ ///
+ /// INITIALISIERUNG:
+ /// - Collection Initializer: Elegante Syntax für große Datenmengen
+ /// - Compile-Time: Alle Daten werden zur Compile-Zeit in Assembly eingebettet
+ /// - Memory Efficient: Daten werden nur einmal geladen und geteilt
+ ///
+ /// ZUGRIFF:
+ /// var elements = PeriodicTableData.Elements;
+ /// var hydrogen = elements.First(e => e.Symbol == "H");
+ ///
public static List Elements { get; } = new List
{
- // Erste Periode
- new Element( 1, "H", "Wasserstoff", 1.008, 2.20, 0.000, "Nichtmetall", 0, 0),
- new Element( 2, "He", "Helium", 4.003, 0.00, 0.001, "Edelgas", 0, 17),
+ // ===== ERSTE PERIODE =====
+ // Die einfachsten Elemente: Wasserstoff und Helium
+ // Besonderheiten: Nur 1s-Orbitale gefüllt, einzigartige Eigenschaften
+
+ new Element( 1, "H", "Wasserstoff", 1.008, 2.20, 0.000, "Nichtmetall", 0, 0), // Leichtestes Element, Grundbaustein des Universums
+ new Element( 2, "He", "Helium", 4.003, 0.00, 0.001, "Edelgas", 0, 17), // Edelgas mit vollständiger Schale, chemisch inert
- // Zweite Periode
- new Element( 3, "Li", "Lithium", 6.940, 0.98, 0.534, "Alkalimetall", 1, 0),
- new Element( 4, "Be", "Beryllium", 9.012, 1.57, 1.850, "Erdalkalimetall", 1, 1),
- new Element( 5, "B", "Bor", 10.810,2.04, 2.340, "Halbmetall", 1, 12),
- new Element( 6, "C", "Kohlenstoff", 12.011,2.55, 2.267, "Nichtmetall", 1, 13),
- new Element( 7, "N", "Stickstoff", 14.007,3.04, 0.001, "Nichtmetall", 1, 14),
- new Element( 8, "O", "Sauerstoff", 15.999,3.44, 0.001, "Nichtmetall", 1, 15),
- new Element( 9, "F", "Fluor", 18.998,3.98, 0.002, "Halogen", 1, 16),
- new Element( 10, "Ne", "Neon", 20.180,0.00, 0.001, "Edelgas", 1, 17),
+ // ===== ZWEITE PERIODE =====
+ // Elemente mit 2 Elektronenschalen (1s² + 2s/2p)
+ // Wichtige biologische und technische Elemente
+
+ new Element( 3, "Li", "Lithium", 6.940, 0.98, 0.534, "Alkalimetall", 1, 0), // Leichtestes Metall, wichtig für Batterien
+ new Element( 4, "Be", "Beryllium", 9.012, 1.57, 1.850, "Erdalkalimetall", 1, 1), // Leicht aber giftig, Luft-/Raumfahrt
+ new Element( 5, "B", "Bor", 10.810,2.04, 2.340, "Halbmetall", 1, 12), // Grenze zwischen Metall/Nichtmetall
+ new Element( 6, "C", "Kohlenstoff", 12.011,2.55, 2.267, "Nichtmetall", 1, 13), // Basis allen Lebens, vielfältigste Chemie
+ new Element( 7, "N", "Stickstoff", 14.007,3.04, 0.001, "Nichtmetall", 1, 14), // 78% der Atmosphäre, wichtig für Proteine
+ new Element( 8, "O", "Sauerstoff", 15.999,3.44, 0.001, "Nichtmetall", 1, 15), // Lebenswichtig, 21% der Atmosphäre
+ new Element( 9, "F", "Fluor", 18.998,3.98, 0.002, "Halogen", 1, 16), // Höchste Elektronegativität, sehr reaktiv
+ new Element( 10, "Ne", "Neon", 20.180,0.00, 0.001, "Edelgas", 1, 17), // Leuchtreklame, chemisch inert
- // Dritte Periode
- new Element( 11, "Na", "Natrium", 22.990,0.93, 0.971, "Alkalimetall", 2, 0),
- new Element( 12, "Mg", "Magnesium", 24.305,1.31, 1.738, "Erdalkalimetall", 2, 1),
- new Element( 13, "Al", "Aluminium", 26.982,1.61, 2.698, "Post-Übergangsmetall",2, 12),
- new Element( 14, "Si", "Silizium", 28.085,1.90, 2.329, "Halbmetall", 2, 13),
- new Element( 15, "P", "Phosphor", 30.974,2.19, 1.820, "Nichtmetall", 2, 14),
- new Element( 16, "S", "Schwefel", 32.060,2.58, 2.067, "Nichtmetall", 2, 15),
+ // ===== DRITTE PERIODE =====
+ // Erste Periode mit d-Orbital-Möglichkeiten
+ // Viele technisch wichtige Elemente (Aluminium, Silizium)
+
+ new Element( 11, "Na", "Natrium", 22.990,0.93, 0.971, "Alkalimetall", 2, 0), // Kochsalz, lebenswichtig für Nerven
+ new Element( 12, "Mg", "Magnesium", 24.305,1.31, 1.738, "Erdalkalimetall", 2, 1), // Chlorophyll-Zentrum, leichte Legierungen
+ new Element( 13, "Al", "Aluminium", 26.982,1.61, 2.698, "Post-Übergangsmetall",2, 12), // Häufigstes Metall der Erdkruste
+ new Element( 14, "Si", "Silizium", 28.085,1.90, 2.329, "Halbmetall", 2, 13), // Basis der Halbleiter-Technologie
+ new Element( 15, "P", "Phosphor", 30.974,2.19, 1.820, "Nichtmetall", 2, 14), // DNA/RNA, Energie-Übertragung (ATP)
+ new Element( 16, "S", "Schwefel", 32.060,2.58, 2.067, "Nichtmetall", 2, 15), // Proteine, Vulkanismus
new Element( 17, "Cl", "Chlor", 35.450,3.16, 0.003, "Halogen", 2, 16),
new Element( 18, "Ar", "Argon", 39.948,0.00, 0.002, "Edelgas", 2, 17),
diff --git a/Project_Periodensystem.View/NavigationService.cs b/Project_Periodensystem.View/NavigationService.cs
index 1f06609..9468956 100644
--- a/Project_Periodensystem.View/NavigationService.cs
+++ b/Project_Periodensystem.View/NavigationService.cs
@@ -8,30 +8,126 @@ using Project_Periodensystem.Controller;
namespace Project_Periodensystem.View
{
///
- /// Navigation Service Implementation im View-Layer
- /// Implementiert INavigationService Interface vom Controller
- /// SAUBERE TRENNUNG: Controller definiert WAS, View definiert WIE
+ /// 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
///
public class NavigationService : INavigationService
{
+ // ===== PRIVATE FELDER =====
+
+ ///
+ /// 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
+ ///
private readonly MainWindow _mainWindow;
+
+ ///
+ /// 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
+ ///
private PeriodensystemController? _dataController;
+ // ===== KONSTRUKTOR UND INITIALISIERUNG =====
+
///
- /// Konstruktor
+ /// 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
///
+ /// Das Hauptfenster der Avalonia-Anwendung
+ /// Wenn mainWindow null ist
public NavigationService(MainWindow mainWindow)
{
_mainWindow = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow));
- Logger.Log("NavigationService initialisiert - saubere Interface-Trennung");
+ Logger.Log("NavigationService initialisiert - implementiert Interface-basierte Navigation");
}
///
- /// Data Controller setzen (löst zirkuläre Abhängigkeit)
+ /// 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
///
+ /// Der PeriodensystemController für Datenzugriff
+ /// Wenn dataController null ist
public void SetDataController(PeriodensystemController dataController)
{
_dataController = dataController ?? throw new ArgumentNullException(nameof(dataController));
+ Logger.Log("DataController in NavigationService gesetzt - zirkuläre Abhängigkeit aufgelöst");
}
///
diff --git a/Project_Periodensystem.View/PeriodicTablePage.axaml.cs b/Project_Periodensystem.View/PeriodicTablePage.axaml.cs
index 794754a..eef5190 100644
--- a/Project_Periodensystem.View/PeriodicTablePage.axaml.cs
+++ b/Project_Periodensystem.View/PeriodicTablePage.axaml.cs
@@ -37,21 +37,13 @@ namespace Project_Periodensystem.View
periodicGrid = this.FindControl("PeriodicGrid");
}
- ///
- /// Controller setzen (Dependency Injection für MVC)
- ///
public void SetController(PeriodensystemController controller)
{
_controller = controller ?? throw new ArgumentNullException(nameof(controller));
Logger.Log("PeriodicTablePage: Controller gesetzt (MVC-Pattern)");
-
- // Elemente laden und anzeigen
LoadAndDisplayElements();
}
- ///
- /// Lädt Elemente über Controller und zeigt sie an
- ///
private void LoadAndDisplayElements()
{
try
@@ -62,7 +54,6 @@ namespace Project_Periodensystem.View
return;
}
- // Daten über Controller laden (nicht direkt!)
var elements = _controller.GetAllElements();
if (!elements.Any())
@@ -71,7 +62,6 @@ namespace Project_Periodensystem.View
return;
}
- // Datenvalidierung über Controller
if (!_controller.ValidateData())
{
Logger.Log("Datenvalidierung fehlgeschlagen");
@@ -80,7 +70,6 @@ namespace Project_Periodensystem.View
Logger.Log($"Lade {elements.Count} Elemente in das Grid");
- // UI-Update für jedes Element
int successCount = 0;
foreach (var element in elements)
{
@@ -96,8 +85,6 @@ namespace Project_Periodensystem.View
}
Logger.Log($"{successCount} von {elements.Count} Elementen erfolgreich geladen");
-
- // Legend-Buttons sammeln für Highlighting-Funktionalität
CollectLegendButtons();
}
catch (Exception ex)
@@ -106,10 +93,6 @@ namespace Project_Periodensystem.View
}
}
- ///
- /// Erstellt UI-Button für ein Element (nur View-Logik)
- ///
- /// Element für das der Button erstellt wird
private void CreateElementButton(Element element)
{
if (element == null)
@@ -118,15 +101,12 @@ namespace Project_Periodensystem.View
return;
}
- // UI-Komponenten erstellen
var button = new Button { Classes = { "ElementTile" } };
var panel = new StackPanel();
- // Button-Referenz für Highlighting speichern
- button.Tag = element; // Element-Daten im Tag speichern
+ button.Tag = element;
_elementButtons.Add(button);
- // Hintergrundfarbe über Converter setzen
var backgroundColor = new SeriesToColorConverter()
.Convert(element.Series, typeof(Brush), null, CultureInfo.InvariantCulture) as Brush;
@@ -135,7 +115,6 @@ namespace Project_Periodensystem.View
button.Background = backgroundColor;
}
- // Text-Elemente erstellen
var symbolText = new TextBlock
{
Text = element.Symbol,
@@ -152,12 +131,10 @@ namespace Project_Periodensystem.View
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center
};
- // Layout zusammenbauen
- panel.Children.Add(numberText); // Number on top
- panel.Children.Add(symbolText); // Symbol below
+ panel.Children.Add(numberText);
+ panel.Children.Add(symbolText);
button.Content = panel;
- // Grid-Position setzen (0-basiert)
int gridRow = element.Row;
int gridColumn = element.Column;
@@ -166,7 +143,6 @@ namespace Project_Periodensystem.View
Grid.SetRow(button, gridRow);
Grid.SetColumn(button, gridColumn);
- // Button zum Grid hinzufügen
if (periodicGrid != null)
{
periodicGrid.Children.Add(button);