diff --git a/Project_Periodensystem.Controller/PeriodensystemController.cs b/Project_Periodensystem.Controller/PeriodensystemController.cs
index 3c363d7..49e70ec 100644
--- a/Project_Periodensystem.Controller/PeriodensystemController.cs
+++ b/Project_Periodensystem.Controller/PeriodensystemController.cs
@@ -1,17 +1,196 @@
-using System.Collections.ObjectModel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
using Project_Periodensystem.Model;
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
+ ///
public class PeriodensystemController
{
- public ObservableCollection Elements { get; }
+ // Nullable Field um Warning zu vermeiden
+ private List _elements = new List();
+ ///
+ /// Konstruktor - initialisiert den Controller
+ ///
public PeriodensystemController()
{
- // Gießt die statische List<> in eine ObservableCollection
- Elements = new ObservableCollection(PeriodicTableData.Elements);
+ LoadElements();
+ }
+
+ ///
+ /// Lädt alle Elemente über den Persistence-Layer
+ ///
+ private void LoadElements()
+ {
+ try
+ {
+ // Verwende die korrekte statische Methode aus PeriodicTableData
+ _elements = PeriodicTableData.Elements.ToList();
+ Logger.Log($"Controller: {_elements.Count} Elemente erfolgreich geladen");
+ }
+ catch (Exception ex)
+ {
+ Logger.Log($"EXCEPTION in LoadElements: {ex.Message}");
+ _elements = new List();
+ }
+ }
+
+ ///
+ /// Gibt alle verfügbaren Elemente zurück
+ ///
+ /// Liste aller Elemente
+ public List GetAllElements()
+ {
+ return _elements;
+ }
+
+ ///
+ /// 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
+ ///
+ /// 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));
+ }
+
+ ///
+ /// Filtert Elemente nach Serie
+ ///
+ /// 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();
+ }
+
+ ///
+ /// 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)
+ ///
+ public void RefreshData()
+ {
+ Logger.Log("Daten werden neu geladen...");
+ LoadElements();
+ }
+
+ ///
+ /// Gibt die Anzahl der geladenen Elemente zurück
+ ///
+ /// Anzahl der Elemente
+ public int GetElementCount()
+ {
+ return _elements.Count;
}
}
}
diff --git a/Project_Periodensystem.Model/Logger.cs b/Project_Periodensystem.Model/Logger.cs
new file mode 100644
index 0000000..559d22e
--- /dev/null
+++ b/Project_Periodensystem.Model/Logger.cs
@@ -0,0 +1,136 @@
+using System;
+using System.IO;
+
+namespace Project_Periodensystem.Model
+{
+ ///
+ /// Einfacher Logger für Debug-Ausgaben und Fehlerprotokollierung
+ ///
+ public static class Logger
+ {
+ private static readonly string LogFilePath = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+ "Periodensystem", "app.log");
+
+ ///
+ /// Statischer Initializer - erstellt Log-Verzeichnis
+ ///
+ static Logger()
+ {
+ try
+ {
+ var logDirectory = Path.GetDirectoryName(LogFilePath);
+ if (logDirectory != null && !Directory.Exists(logDirectory))
+ {
+ Directory.CreateDirectory(logDirectory);
+ }
+ }
+ catch
+ {
+ // Falls Log-Datei nicht erstellt werden kann, nur Konsole verwenden
+ }
+ }
+
+ ///
+ /// Protokolliert eine Nachricht sowohl in Konsole als auch Datei
+ ///
+ /// Zu protokollierende Nachricht
+ public static void Log(string message)
+ {
+ if (string.IsNullOrWhiteSpace(message))
+ return;
+
+ var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
+ var logEntry = $"[{timestamp}] {message}";
+
+ // Konsolen-Ausgabe (für Debug)
+ Console.WriteLine(logEntry);
+
+ // Datei-Ausgabe (für Persistenz)
+ try
+ {
+ File.AppendAllText(LogFilePath, logEntry + Environment.NewLine);
+ }
+ catch
+ {
+ // Fehler beim Schreiben ignorieren um App nicht zum Absturz zu bringen
+ }
+ }
+
+ ///
+ /// Protokolliert eine Exception mit Stack-Trace
+ ///
+ /// Exception die protokolliert werden soll
+ /// Zusätzlicher Kontext
+ public static void LogException(Exception ex, string context = "")
+ {
+ if (ex == null)
+ {
+ Log("Null-Exception übergeben");
+ return;
+ }
+
+ var message = string.IsNullOrWhiteSpace(context)
+ ? $"EXCEPTION: {ex.Message}\nStack: {ex.StackTrace}"
+ : $"EXCEPTION in {context}: {ex.Message}\nStack: {ex.StackTrace}";
+
+ Log(message);
+ }
+
+ ///
+ /// Protokolliert eine Warnung
+ ///
+ /// Warnung
+ public static void LogWarning(string message)
+ {
+ Log($"WARNING: {message}");
+ }
+
+ ///
+ /// Protokolliert einen Fehler
+ ///
+ /// Fehlermeldung
+ public static void LogError(string message)
+ {
+ Log($"ERROR: {message}");
+ }
+
+ ///
+ /// Protokolliert Debug-Informationen (nur in Debug-Build)
+ ///
+ /// Debug-Nachricht
+ [System.Diagnostics.Conditional("DEBUG")]
+ public static void LogDebug(string message)
+ {
+ Log($"DEBUG: {message}");
+ }
+
+ ///
+ /// Löscht die Log-Datei (für Cleanup)
+ ///
+ public static void ClearLog()
+ {
+ try
+ {
+ if (File.Exists(LogFilePath))
+ {
+ File.Delete(LogFilePath);
+ Log("Log-Datei gelöscht");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log($"Fehler beim Löschen der Log-Datei: {ex.Message}");
+ }
+ }
+
+ ///
+ /// Gibt den Pfad zur Log-Datei zurück
+ ///
+ /// Vollständiger Pfad zur Log-Datei
+ public static string GetLogFilePath()
+ {
+ return LogFilePath;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Project_Periodensystem.Model/Theme.cs b/Project_Periodensystem.Model/Theme.cs
deleted file mode 100644
index b54600b..0000000
--- a/Project_Periodensystem.Model/Theme.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Project_Periodensystem.Model
-{
- public enum AppTheme
- {
- Dark,
- Light,
- Classic
- }
-}
\ No newline at end of file
diff --git a/Project_Periodensystem.View/AboutPage.axaml b/Project_Periodensystem.View/AboutPage.axaml
index 5dfe90a..fd586d8 100644
--- a/Project_Periodensystem.View/AboutPage.axaml
+++ b/Project_Periodensystem.View/AboutPage.axaml
@@ -1,19 +1,19 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
-
-
-
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
\ No newline at end of file
diff --git a/Project_Periodensystem.View/AboutPage.axaml.cs b/Project_Periodensystem.View/AboutPage.axaml.cs
index fee854f..79a2ef0 100644
--- a/Project_Periodensystem.View/AboutPage.axaml.cs
+++ b/Project_Periodensystem.View/AboutPage.axaml.cs
@@ -8,44 +8,67 @@ using Project_Periodensystem.Model;
namespace Project_Periodensystem.View
{
+ ///
+ /// Code-Behind für die About-Seite
+ ///
public partial class AboutPage : UserControl
{
+ ///
+ /// Konstruktor
+ ///
public AboutPage()
{
InitializeComponent();
}
- protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
- {
- base.OnAttachedToVisualTree(e);
-
- if (this.GetVisualRoot() is MainWindow mainWindow)
- {
- mainWindow.UpdateTheme(MainWindow.CurrentTheme);
- }
- }
-
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
+ ///
+ /// Zurück-Button - Navigation zur Landing Page
+ ///
private void BackButton_Click(object? sender, RoutedEventArgs e)
{
- if (MainWindow.Instance != null)
+ try
{
- MainWindow.Instance.ShowLandingPage();
+ var mainWindow = TopLevel.GetTopLevel(this) as Window;
+ if (mainWindow != null)
+ {
+ var landingPage = new LandingPage();
+ mainWindow.Content = landingPage;
+ Logger.Log("Navigation zurück zur Landing Page");
+ }
+ }
+ catch (System.Exception ex)
+ {
+ Logger.Log($"Fehler bei Navigation zurück: {ex.Message}");
}
}
+ ///
+ /// Event-Handler für Theme-Button - VEREINHEITLICHT mit anderen Seiten
+ ///
private void ThemeButton_Click(object? sender, RoutedEventArgs e)
{
- var themes = Enum.GetValues();
- MainWindow.CurrentTheme = themes[(Array.IndexOf(themes, MainWindow.CurrentTheme) + 1) % themes.Length];
-
- if (MainWindow.Instance != null)
+ try
{
- MainWindow.Instance.UpdateTheme(MainWindow.CurrentTheme);
+ // GLEICHE LOGIK wie auf LandingPage und PeriodicTablePage
+ var app = Application.Current;
+ if (app != null)
+ {
+ var currentTheme = app.ActualThemeVariant;
+ app.RequestedThemeVariant = currentTheme == Avalonia.Styling.ThemeVariant.Dark
+ ? Avalonia.Styling.ThemeVariant.Light
+ : Avalonia.Styling.ThemeVariant.Dark;
+
+ Logger.Log($"Theme gewechselt zu: {app.RequestedThemeVariant}");
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Log($"Fehler beim Theme-Wechsel: {ex.Message}");
}
}
}
diff --git a/Project_Periodensystem.View/App.axaml b/Project_Periodensystem.View/App.axaml
index 09e0eda..aae0356 100644
--- a/Project_Periodensystem.View/App.axaml
+++ b/Project_Periodensystem.View/App.axaml
@@ -1,7 +1,9 @@
-
-
-
+ x:Class="Project_Periodensystem.View.App"
+ RequestedThemeVariant="Dark">
+
+
+
+
diff --git a/Project_Periodensystem.View/App.axaml.cs b/Project_Periodensystem.View/App.axaml.cs
index 1b535e1..af02b32 100644
--- a/Project_Periodensystem.View/App.axaml.cs
+++ b/Project_Periodensystem.View/App.axaml.cs
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
+using Project_Periodensystem.Model;
namespace Project_Periodensystem.View
{
@@ -15,7 +16,11 @@ namespace Project_Periodensystem.View
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
+ // Standard Dark Theme beim Start
+ RequestedThemeVariant = Avalonia.Styling.ThemeVariant.Dark;
+
desktop.MainWindow = new MainWindow();
+ Logger.Log("Application initialized with Dark theme");
}
base.OnFrameworkInitializationCompleted();
diff --git a/Project_Periodensystem.View/LandingPage.axaml b/Project_Periodensystem.View/LandingPage.axaml
index 695ac68..500552b 100644
--- a/Project_Periodensystem.View/LandingPage.axaml
+++ b/Project_Periodensystem.View/LandingPage.axaml
@@ -1,13 +1,15 @@
-
+
@@ -17,50 +19,53 @@
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
+
+
diff --git a/Project_Periodensystem.View/LandingPage.axaml.cs b/Project_Periodensystem.View/LandingPage.axaml.cs
index 0329116..4c43f1e 100644
--- a/Project_Periodensystem.View/LandingPage.axaml.cs
+++ b/Project_Periodensystem.View/LandingPage.axaml.cs
@@ -1,79 +1,95 @@
using Avalonia;
using Avalonia.Controls;
-using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Interactivity;
-using Avalonia.Markup.Xaml;
-using Avalonia.Media;
-using Avalonia.VisualTree;
using Project_Periodensystem.Model;
-using System;
-using System.Collections.Generic;
namespace Project_Periodensystem.View
{
+ ///
+ /// Code-Behind für die Landing Page
+ ///
public partial class LandingPage : UserControl
{
- private readonly Random random = new();
- private readonly Dictionary themeColors;
- private DateTime lastClickTime = DateTime.MinValue;
- private const int DEBOUNCE_MS = 500;
-
+ ///
+ /// Konstruktor
+ ///
public LandingPage()
{
- Logger.Log($"=== LandingPage wird initialisiert am {DateTime.Now:dd.MM.yyyy HH:mm:ss} ===");
InitializeComponent();
-
- themeColors = new Dictionary
- {
- { AppTheme.Dark, "#5C5144" },
- { AppTheme.Light, "#E8DFD8" },
- { AppTheme.Classic, "#7B8B6F" }
- };
-
- Logger.Log("LandingPage initialisiert");
}
- private void InitializeComponent()
+ ///
+ /// Event-Handler für Periodensystem-Button
+ ///
+ private void PeriodicTableButton_Click(object? sender, RoutedEventArgs e)
{
- AvaloniaXamlLoader.Load(this);
- }
-
- private void ThemeButton_Click(object? sender, RoutedEventArgs e)
- {
- var themes = Enum.GetValues();
- MainWindow.CurrentTheme = themes[(Array.IndexOf(themes, MainWindow.CurrentTheme) + 1) % themes.Length];
-
- if (MainWindow.Instance != null)
+ try
{
- MainWindow.Instance.UpdateTheme(MainWindow.CurrentTheme);
+ var mainWindow = TopLevel.GetTopLevel(this) as Window;
+ if (mainWindow != null)
+ {
+ var periodicTablePage = new PeriodicTablePage();
+ mainWindow.Content = periodicTablePage;
+ Logger.Log("Navigation zum Periodensystem");
+ }
+ }
+ catch (System.Exception ex)
+ {
+ Logger.Log($"Fehler bei Navigation zum Periodensystem: {ex.Message}");
}
}
- private void StartButton_Click(object? sender, RoutedEventArgs e)
+ ///
+ /// Event-Handler für About-Button
+ ///
+ private void AboutButton_Click(object? sender, RoutedEventArgs e)
{
- // Add multiple ways to see if this method is called
- System.Diagnostics.Debug.WriteLine("StartButton_Click CALLED!");
- Console.WriteLine("StartButton_Click CALLED!");
- // Remove the MessageBox line - it's not available
-
- Logger.Log("=== StartButton_Click CALLED ===");
-
- try
+ try
{
- if (MainWindow.Instance != null)
+ var mainWindow = TopLevel.GetTopLevel(this) as Window;
+ if (mainWindow != null)
{
- Logger.Log("Found MainWindow instance - calling ShowPeriodicTable");
- MainWindow.Instance.ShowPeriodicTable();
- Logger.Log("ShowPeriodicTable called successfully");
+ var aboutPage = new AboutPage();
+ mainWindow.Content = aboutPage;
+ Logger.Log("Navigation zur About-Seite");
+ }
+ }
+ catch (System.Exception ex)
+ {
+ Logger.Log($"Fehler bei Navigation zu About: {ex.Message}");
+ }
+ }
+
+ ///
+ /// Event-Handler für Theme-Button
+ ///
+ private void ThemeButton_Click(object? sender, RoutedEventArgs e)
+ {
+ try
+ {
+ Logger.Log("Theme-Button geklickt");
+
+ var app = Application.Current;
+ if (app != null)
+ {
+ var currentTheme = app.ActualThemeVariant;
+ Logger.Log($"Aktuelles Theme: {currentTheme}");
+
+ var newTheme = currentTheme == Avalonia.Styling.ThemeVariant.Dark
+ ? Avalonia.Styling.ThemeVariant.Light
+ : Avalonia.Styling.ThemeVariant.Dark;
+
+ app.RequestedThemeVariant = newTheme;
+ Logger.Log($"Theme gewechselt zu: {newTheme}");
}
else
{
- Logger.Log("MainWindow.Instance is null!");
+ Logger.Log("Application.Current ist null!");
}
}
- catch (Exception ex)
+ catch (System.Exception ex)
{
- Logger.Log($"ERROR in StartButton_Click: {ex.Message}");
+ Logger.Log($"Fehler beim Theme-Wechsel: {ex.Message}");
}
}
}
diff --git a/Project_Periodensystem.View/MainWindow.axaml.cs b/Project_Periodensystem.View/MainWindow.axaml.cs
index 13df0ce..26e7050 100644
--- a/Project_Periodensystem.View/MainWindow.axaml.cs
+++ b/Project_Periodensystem.View/MainWindow.axaml.cs
@@ -1,152 +1,65 @@
using Avalonia;
using Avalonia.Controls;
-using Avalonia.Media;
-using Avalonia.VisualTree;
-using Avalonia.Threading;
using Project_Periodensystem.Model;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using static Project_Periodensystem.Model.AppTheme;
namespace Project_Periodensystem.View
{
+ ///
+ /// Vereinfachtes MainWindow - nur noch Container für Content
+ ///
public partial class MainWindow : Window
{
private ContentControl? mainContent;
- public static AppTheme CurrentTheme { get; set; } = AppTheme.Dark;
- public static MainWindow? Instance { get; private set; } // Add this line
-
- public static Dictionary ThemeColors { get; } = new()
- {
- { AppTheme.Dark, ("#2F2F2F", "#FFFFFF") },
- { AppTheme.Light, ("#FFFFFF", "#000000") },
- { AppTheme.Classic, ("#E8E8E8", "#000000") }
- };
public MainWindow()
{
InitializeComponent();
- Instance = this; // Set the static reference
mainContent = this.FindControl("MainContent");
ShowLandingPage();
}
+ ///
+ /// Zeigt die Landing Page an
+ ///
public void ShowLandingPage()
{
- mainContent!.Content = new LandingPage();
- Dispatcher.UIThread.Post(() => UpdateTheme(CurrentTheme), DispatcherPriority.Loaded);
+ if (mainContent != null)
+ {
+ mainContent.Content = new LandingPage();
+ Logger.Log("Landing Page angezeigt");
+ }
}
+ ///
+ /// Zeigt das Periodensystem an
+ ///
public void ShowPeriodicTable()
{
Logger.Log("ShowPeriodicTable called");
try
{
- mainContent!.Content = new PeriodicTablePage();
- Logger.Log("PeriodicTablePage created and set");
- Dispatcher.UIThread.Post(() => UpdateTheme(CurrentTheme), DispatcherPriority.Loaded);
- Logger.Log("Theme update posted");
+ if (mainContent != null)
+ {
+ mainContent.Content = new PeriodicTablePage();
+ Logger.Log("PeriodicTablePage created and set");
+ }
}
- catch (Exception ex)
+ catch (System.Exception ex)
{
Logger.Log($"Error in ShowPeriodicTable: {ex.Message}");
}
}
+ ///
+ /// Zeigt die About Page an
+ ///
public void ShowAboutPage()
{
- mainContent!.Content = new AboutPage();
- Dispatcher.UIThread.Post(() => UpdateTheme(CurrentTheme), DispatcherPriority.Loaded);
- }
-
- public void UpdateTheme(AppTheme theme)
- {
- CurrentTheme = theme;
- if (mainContent?.Content is UserControl control)
+ if (mainContent != null)
{
- var (background, foreground) = ThemeColors[theme];
- control.Background = new SolidColorBrush(Color.Parse(background));
-
- // For PeriodicTablePage, use a timer to ensure visual tree is ready
- if (control is PeriodicTablePage)
- {
- // Wait a bit longer for the visual tree to be fully constructed
- var timer = new System.Timers.Timer(100); // 100ms delay
- timer.Elapsed += (sender, e) =>
- {
- timer.Stop();
- timer.Dispose();
-
- Dispatcher.UIThread.Post(() =>
- {
- try
- {
- var allButtons = control.GetVisualDescendants().OfType