Inhalt

Aktueller Ordner: duesseldorfer-schuelerinventar-visualstudio-client
⬅ Übergeordnet

README.md

DÜSK - WPF Desktop App für Windows




DÜSK ist eine professionelle Desktop-Anwendung für Windows zur Erfassung und Auswertung von Selbst- und Fremdeinschätzungen von Schülerkompetenzen. Die App wurde mit .NET 8.0 und WPF (Windows Presentation Foundation) entwickelt und bietet eine moderne, flüssige Benutzeroberfläche mit nativer Windows-Integration.

---

📋 Inhaltsverzeichnis



- Überblick
- Features
- Technologie-Stack
- Screenshots
- API-Dokumentation
- Datenbankstruktur
- Installation
- Projektstruktur
- Berechnungslogik
- Konfiguration
- Build & Deployment
- Entwicklung
- Fehlerbehandlung


---

🎯 Überblick



DÜSK (Düsseldorfer Schülerinventar) ist ein diagnostisches Instrument zur Erfassung von Schülerkompetenzen in sechs Bereichen:

| Bereich | Beschreibung |
|---------|--------------|
| 1. Arbeitsverhalten | Zuverlässigkeit, Arbeitstempo, Planung, Organisation |
| 2. Lernverhalten | Selbstständigkeit, Belastbarkeit, Konzentration, Merkfähigkeit |
| 3. Sozialverhalten | Teamfähigkeit, Hilfsbereitschaft, Kommunikation, Konfliktfähigkeit |
| 4. Fachkompetenz | Schreiben, Lesen, Mathematik, Naturwissenschaften, Fremdsprachen |
| 5. Personale Kompetenz | Kreativität, Problemlösung, Abstraktion, Reflexion |
| 6. Methodenkompetenz | Präsentation, PC-Kenntnisse, fächerübergreifendes Denken |

Die Anwendung ermöglicht den Vergleich von Selbsteinschätzung (SE) und Fremdeinschätzung (FE) mit Normtabellen für Hauptschulen (HS) und Förderschulen (FS).

---

✨ Features



Kernfunktionen


- ✅ Login/Logout mit persistenter Session-Speicherung
- ✅ CRUD-Operationen für Schülerprofile (Erstellen, Lesen, Aktualisieren, Löschen)
- ✅ 36 Items pro Einschätzung (4-stufige Likert-Skala: 1-4)
- ✅ Automatische Kompetenzberechnung aus 72 Items
- ✅ Normwertvergleich (HS/FS Normtabellen)
- ✅ Profilansicht mit Tabellen, interaktiven Diagrammen und Textinterpretation

Erweiterte Funktionen


- 📊 Zeitreihenanalyse für Gruppenentwicklung über Zeit
- 📈 Vergleichsdiagramme (SE vs. FE mit Pearson-Korrelation)
- 📐 Korrelationsberechnung mit statistischer Interpretation
- 📑 Exportfunktion (CSV, PDF in Entwicklung)
- 🔍 Such- und Filterfunktionen (nach Namen und Gruppen)
- 📁 Gruppenverwaltung (CRUD mit Umbenennung)
- 🌙 Modernes Fluent Design (Windows 11 optimiert)
- 💾 Persistente Speicherung (Session, Fensterposition)
- ⌨️ Tastatur-Shortcuts (Enter für Login, etc.)
- 🖥️ Native Windows-Integration (Taskbar, Fensterverwaltung)

---

🛠 Technologie-Stack



WPF App



| Komponente | Technologie | Version |
|------------|-------------|---------|
| Framework | .NET 8.0 | 8.0 |
| Sprache | C# | 12.0 |
| UI-Framework | WPF | - |
| HTTP-Client | HttpClient | .NET native |
| JSON-Parser | Newtonsoft.Json | 13.0.3 |
| Charts | LiveCharts.Wpf | 0.9.7 |
| Behaviors | Microsoft.Xaml.Behaviors.Wpf | 1.1.77 |
| Build-Tool | MSBuild | - |
| Mindest-Windows | Windows 10 | 1809+ |

Server (PHP API)



| Komponente | Technologie |
|------------|-------------|
| Backend | PHP 7.4+ |
| Datenbank | MySQL 5.7+ |
| Webserver | Apache/Nginx |
| Format | JSON |

---

📡 API-Dokumentation



Die REST-API ist unter https://paul-koop.org/api/ verfügbar.

Authentifizierung



#### POST /api_login.php

`json
// Request
{
"username": "gast",
"password": "gast"
}

// Response (Success)
{
"success": true,
"userID": "12345",
"session": "abc123def456789"
}

// Response (Error)
{
"success": false,
"error": "Invalid credentials"
}
`

Profile-Endpunkte



> Wichtig: Alle Profile-Endpunkte benötigen die Header:
> - X-User-ID: Benutzer-ID aus Login
> - X-Session: Session-Token aus Login

#### GET /api_profiles.php

Response: Array aller Profile des Benutzers

`json
[
{
"profilID": "1",
"name": "Max Mustermann",
"gruppename": "Klasse 8a",
"gruppeID": "5",
"created_at": "2024-01-15 10:30:00",
"item1": 4, "item2": 3, ..., "item36": 2,
"feitem1": 3, "feitem2": 4, ..., "feitem36": 3
}
]
`

#### GET /api_profiles.php?id={profileId}

Response: Einzelnes Profil

#### POST /api_profiles.php

Request Body: Vollständiges Profil-Objekt (alle 72 Items)
Response: 200 OK bei Erfolg

#### PUT /api_profiles.php

Request Body: Aktualisiertes Profil-Objekt
Response: 200 OK bei Erfolg

#### DELETE /api_profiles.php?id={profileId}

Response: 200 OK bei Erfolg

Gruppen-Endpunkte



#### GET /api_groups.php

Response:
`json
[
{"gruppeID": 1, "name": "Klasse 8a"},
{"gruppeID": 2, "name": "Klasse 8b"},
{"gruppeID": 3, "name": "Klasse 9a"}
]
`

#### POST /api_groups.php

Request Body: {"name": "Neue Gruppe"}
Response: 200 OK bei Erfolg

#### DELETE /api_groups.php?id={groupId}

Response: 200 OK bei Erfolg

---

🗄 Datenbankstruktur



ER-Diagramm



`
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ users │ │ groups │ │ profiles │
├─────────────┤ ├─────────────┤ ├─────────────┤
│ userID (PK) │────<│ userID (FK) │ │ profilID(PK)│
│ username │ │ gruppeID(PK)│<────│ userID (FK) │
│ password │ │ name │ │ gruppeID(FK)│
│ session │ │ created_at │ │ name │
│ created_at │ └─────────────┘ │ item1-36 │
└─────────────┘ │ feitem1-36 │
│ created_at │
│ updated_at │
└─────────────┘
`

SQL-Schema



`sql
-- Users Tabelle
CREATE TABLE users (
userID INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
session_token VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Groups Tabelle
CREATE TABLE groups (
gruppeID INT AUTO_INCREMENT PRIMARY KEY,
userID INT NOT NULL,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (userID) REFERENCES users(userID) ON DELETE CASCADE,
UNIQUE KEY unique_group_per_user (userID, name)
);

-- Profiles Tabelle
CREATE TABLE profiles (
profilID INT AUTO_INCREMENT PRIMARY KEY,
userID INT NOT NULL,
name VARCHAR(255) NOT NULL,
gruppeID INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- 36 SE-Items (Werte 1-4)
item1 TINYINT DEFAULT 2, item2 TINYINT DEFAULT 2, ..., item36 TINYINT DEFAULT 2,
-- 36 FE-Items (Werte 1-4)
feitem1 TINYINT DEFAULT 2, feitem2 TINYINT DEFAULT 2, ..., feitem36 TINYINT DEFAULT 2,
FOREIGN KEY (userID) REFERENCES users(userID) ON DELETE CASCADE,
FOREIGN KEY (gruppeID) REFERENCES groups(gruppeID) ON DELETE SET NULL
);
`

---

💻 Installation



Voraussetzungen



- Windows 10 oder Windows 11 (64-Bit)
- .NET 8.0 Desktop Runtime (Download)
- Visual Studio 2022 (für Entwicklung, mindestens Community Edition)

Schritt-für-Schritt Installation



`bash

1. Repository klonen


git clone https://github.com/yourusername/duesk-wpf.git
cd duesk-wpf

2. Projekt in Visual Studio öffnen


Doppelklick auf DueskWPF.sln oder DueskWPF.csproj



3. NuGet-Pakete wiederherstellen


dotnet restore

4. App starten (Debug)


dotnet run

5. Release-Build erstellen


dotnet publish -c Release -o ./publish
`

Schnellstart mit der Batch-Datei (Windows)



`batch

Projektstruktur erstellen


create_wpf_project.bat

In das Projekt wechseln


cd duesk-wpf

Build ausführen


dotnet build

App starten


dotnet run
`

---

📁 Projektstruktur



`
duesk-wpf/
├── DueskWPF.csproj # Projektdatei mit NuGet-Abhängigkeiten
├── App.xaml # Anwendungsressourcen & Styles
├── App.xaml.cs # App-Lifecycle (Startup, Exit)
├── Models/
│ ├── LoginResponse.cs # API Response Model für Login
│ ├── Profile.cs # Profil-Datenmodell (72 Items)
│ ├── Group.cs # Gruppen-Datenmodell
│ └── Norms.cs # Normtabellen & Konstanten (HS/FS)
├── Services/
│ ├── SessionManager.cs # Session & persistente Speicherung
│ ├── ApiService.cs # HTTP-API-Kommunikation
│ └── Calculator.cs # Berechnungslogik (Sums, Korrelation)
├── Views/
│ ├── LoginWindow.xaml # Login-Fenster
│ ├── LoginWindow.xaml.cs
│ ├── MainWindow.xaml # Hauptfenster mit Sidebar & Toolbar
│ ├── MainWindow.xaml.cs
│ ├── ProfileDetailWindow.xaml # Profildetails mit Charts & Tabs
│ ├── ProfileDetailWindow.xaml.cs
│ ├── ProfileEditWindow.xaml # Profil erstellen/bearbeiten
│ ├── ProfileEditWindow.xaml.cs
│ ├── GroupManagerWindow.xaml # Gruppenverwaltung (CRUD)
│ ├── GroupManagerWindow.xaml.cs
│ ├── TimeSeriesWindow.xaml # Zeitreihenanalyse mit Chart
│ └── TimeSeriesWindow.xaml.cs
├── Converters/
│ └── BoolToVisibilityConverter.cs # Wertkonverter für UI
└── Resources/
└── Styles.xaml # Globale UI-Styles (Buttons, TextBoxes)
`

---

🧮 Berechnungslogik



Item-zu-Kompetenz-Zuordnung



`csharp
// Kompetenz 1: Arbeitsverhalten (Items 1-10)
for (var i = 0; i < 10; i++) sums[1] += items[i];

// Kompetenz 2: Lernverhalten (Items 11-20)
for (var i = 10; i < 20; i++) sums[2] += items[i];

// Kompetenz 3: Sozialverhalten (Items 21-28 + Items 9-10)
for (var i = 20; i < 28; i++) sums[3] += items[i];
sums[3] += items[8] + items[9];

// Kompetenz 4: Fachkompetenz (Items 29-36)
for (var i = 28; i < 36; i++) sums[4] += items[i];

// Kompetenz 5: Personale Kompetenz (spezifische Items)
sums[5] = items[0] + items[1] + items[5] + items[6] + items[7] +
items[8] + items[9] + items[11] + items[12] + items[13] + items[14];

// Kompetenz 6: Methodenkompetenz (spezifische Items)
sums[6] = items[2] + items[3] + items[4] + items[8] + items[9] +
items[10] + items[16] + items[17];
`

Profilwertberechnung



`csharp
public static int[] CalculateProfileValues(int[] sums, double[][] norm)
{
var values = new int[6];
for (var k = 1; k <= 6; k++)
{
var value = 5;
for (var p = 0; p < 5; p++)
{
if (sums[k] < norm[k - 1][p])
{
value = p + 1;
break;
}
}
values[k - 1] = value;
}
return values;
}
`

Korrelationsberechnung (Pearson)



`csharp
public static double CalculateCorrelation(int[] seValues, int[] feValues)
{
var n = seValues.Length;
double sumSE = 0, sumFE = 0, sumSEFE = 0, sumSE2 = 0, sumFE2 = 0;

for (var i = 0; i < n; i++)
{
sumSE += seValues[i];
sumFE += feValues[i];
sumSEFE += seValues[i] * feValues[i];
sumSE2 += seValues[i] * seValues[i];
sumFE2 += feValues[i] * feValues[i];
}

var numerator = n sumSEFE - sumSE sumFE;
var denominator = Math.Sqrt((n sumSE2 - sumSE sumSE) *
(n sumFE2 - sumFE sumFE));

return Math.Abs(denominator) < 0.0001 ? 0 : numerator / denominator;
}
`

Normtabellen (Vollständig)



| Kompetenz | HS SE Grenzwerte | HS FE Grenzwerte |
|-----------|------------------|------------------|
| Arbeitsverhalten | 21.33, 25.33, 29.33, 33.32, 37.32 | 12.66, 18.16, 23.66, 29.16, 34.66 |
| Lernverhalten | 20.87, 24.95, 29.03, 33.13, 37.18 | 13.33, 18.42, 23.51, 28.60, 33.69 |
| Sozialverhalten | 17.93, 21.37, 24.80, 28.23, 31.67 | 10.75, 15.41, 20.07, 24.73, 29.39 |
| Fachkompetenz | 13.98, 17.71, 21.44, 25.17, 28.90 | 14.22, 15.30, 16.38, 17.46, 18.54 |
| Personale Kompetenz | 24.60, 28.55, 33.04, 37.53, 42.01 | 14.12, 20.21, 26.30, 32.39, 38.48 |
| Methodenkompetenz | 15.53, 18.97, 22.40, 25.83, 29.27 | 10.53, 14.51, 18.49, 22.47, 26.45 |

Für FS (Förderschule) existieren separate Normtabellen.

---

⚙️ Konfiguration



API Base URL ändern



`csharp
// Services/ApiService.cs
private const string BaseUrl = "https://your-server.com/api/";
`

Session-Speicherort



Die Session wird als session.json im Ausführungsverzeichnis gespeichert.

Fensterposition speichern



Die Fenstergröße und -position wird automatisch im session.json gespeichert.

---

🚀 Build & Deployment



Entwicklung



`bash

Build ausführen


dotnet build

App starten


dotnet run

Release-Build


dotnet build -c Release

Publish als Einzeldatei


dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -o ./publish
`

Installer erstellen



Für die Erstellung eines Setup-Installers kann z.B. Inno Setup oder das Visual Studio Installer Projekt verwendet werden.

Systemanforderungen



- Betriebssystem: Windows 10 / Windows 11 (64-Bit)
- .NET Runtime: .NET 8.0 Desktop Runtime
- RAM: mindestens 256 MB
- Festplatte: etwa 50 MB

---

⌨️ Tastatur-Shortcuts



| Shortcut | Aktion |
|----------|--------|
| Enter | Login ausführen (im Login-Fenster) |
| F5 | Profile aktualisieren |
| Ctrl + N | Neues Profil (geplant) |

---

🐛 Fehlerbehandlung



HTTP-Statuscodes



| Code | Bedeutung | Behandlung |
|------|-----------|------------|
| 200 | Erfolg | Daten verarbeiten |
| 400 | Bad Request | Validierungsfehler prüfen |
| 401 | Unauthorized | Neu anmelden |
| 403 | Forbidden | Berechtigung prüfen |
| 404 | Not Found | Ressource existiert nicht |
| 500 | Server Error | Erneut versuchen, Support kontaktieren |

Typische Fehler und Lösungen



`csharp
try
{
var profiles = await _apiService.GetProfilesAsync();
}
catch (HttpRequestException ex)
{
if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
// Session abgelaufen - erneut anmelden
SessionManager.Instance.Clear();
var loginWindow = new LoginWindow();
loginWindow.Show();
Close();
}
else
{
MessageBox.Show($"Fehler: {ex.Message}", "Fehler",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
catch (TaskCanceledException)
{
MessageBox.Show("Verbindung zeitüberschritten", "Fehler",
MessageBoxButton.OK, MessageBoxImage.Error);
}
catch (Exception ex)
{
MessageBox.Show($"Unbekannter Fehler: {ex.Message}", "Fehler",
MessageBoxButton.OK, MessageBoxImage.Error);
}
`

---

🔄 Vergleich der Implementierungen



| Feature | WPF (.NET) | Electron | Flutter | React Native | Swift (iOS) | Java (Swing) |
|---------|------------|----------|---------|--------------|-------------|--------------|
| Windows | ✅ Exzellent | ✅ Gut | ✅ Gut | ❌ | ❌ | ✅ Gut |
| macOS | ❌ | ✅ Gut | ✅ Gut | ❌ | ✅ Exzellent | ✅ Gut |
| Linux | ❌ | ✅ Gut | ✅ Gut | ❌ | ❌ | ✅ Gut |
| iOS | ❌ | ❌ | ✅ Gut | ✅ Gut | ✅ Exzellent | ❌ |
| Android | ❌ | ❌ | ✅ Gut | ✅ Gut | ❌ | ❌ |
| Web | ❌ | ❌ | ✅ Gut | ❌ | ❌ | ❌ |
| Performance | Exzellent | Gut | Exzellent | Gut | Exzellent | Exzellent |
| Installationsgröße | ~15 MB | ~80 MB | ~25 MB | ~30 MB | ~10 MB | ~15 MB |
| Windows-Integration | Exzellent | Gut | Mittel | - | - | Gut |
| Lernkurve | Mittel | Gering | Mittel | Gering | Hoch | Mittel |