Files
ClawdDotNet/docs/archiv/Oberflaechen-Leitfaden.md
RichardandClaude Opus 5.5 6d81693041 Stufe 3 (#764): Avalonia-Fenster entfernt
- Views, ViewModels, Controls, Converters, Styles, Services, Desktop-i18n,
  Schriften und App.axaml raus; Avalonia- und Mvvm-Pakete raus
- ClawdDotNet ohne Schalter: Manager starten (unter systemd ueber den Dienst,
  nie doppelt) und WebUI oeffnen (LauncherRun) - bis die Huelle kommt
- Instanzen laufen immer kopflos; instanceWindows wird gelesen, nicht mehr
  ausgewertet; die Kette 'Fenster nach vorn holen' ist entfernt
- Telegram-Anmeldung nur noch ueber die WebUI (tote Dialog-Rueckrufe raus)
- systemd-Vorlagen im Linux-Paket; Oberflaechen-Leitfaden ins Archiv

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 20:23:12 +02:00

8.6 KiB

Oberfläche — Leitfaden

Archiv seit 2026-10-02 (#764, Stufe 3). Die Avalonia-Fenster, für die dieser Leitfaden galt, sind entfernt. Die einzige Oberfläche ist die WebUI (WebUI-Leitfaden). Aufbewahrt wegen der Begründungen darin.

Für alle, die an src/ClawdDotNet.Desktop arbeiten. Stand: 2026-08-23.


1. Stand

Die Portierung ist abgeschlossen. Es gibt keine Platzhalter mehr und keine WinForms-Vorlage, gegen die man vergleichen könnte: Die alte Oberfläche (ClawdDotNet.csproj, frm_*.cs, UI/, Models/, EmbeddedUI/) ist am 2026-08-23 aus dem Arbeitsbaum entfernt worden. Wer sie doch einmal braucht, findet sie im Tag vor-fruehjahrsputz-2026-08.

Neun Bereiche, alle nativ in Avalonia:

Gruppe Bereich Ansichtsmodell
Arbeit Chat, Agenten, Aufgaben ChatPageViewModel, AgentsPageViewModel, TasksPageViewModel
Analyse Token-Verbrauch, Agenten-Chats TokenUsagePageViewModel, AgentChatsPageViewModel
System Sicherung, Protokoll, Einstellungen, Info BackupPageViewModel, LogPageViewModel, SettingsPageViewModel, InfoPageViewModel

Dazu die Fenster InstancePickerWindow, LicenseWindow, TextEditorWindow und die Dialoge zum Anlegen von Agent, Auftrag und Dienst.

Das Erscheinungsbild folgt dem Entwurf in Mockup/ — wer daran etwas ändert, liest zuerst Mockup/extracted/mockup/Implementierungsleitfaden.md.

Was in der Oberfläche noch fehlt, siehe Roadmap: die Freigabe-Ansicht für gestagte Aufrufe (A2) und die Schaltfläche „Fehler melden" (DC1).


2. Drei Regeln, die nicht verletzt werden dürfen

2.1 Der Schichtschnitt

src/ClawdDotNet.App        ← Fachlogik. KEIN Verweis auf Avalonia. Niemals.
src/ClawdDotNet.Desktop    ← Oberfläche. Darf App und Core verwenden.

ClawdDotNet.App muss ohne Fenster laufen — darauf setzt der geplante systemd-Dienst auf. Sobald dort ein using Avalonia… steht, ist der Schnitt kaputt und fällt erst Wochen später auf.

Faustregel: Alles, was Dateien liest, rechnet oder mit der Engine spricht, gehört nach App. Alles, was etwas anzeigt, nach Desktop.

2.2 Fäden

Ereignisse aus AgentEngine, TaskScanner, OpenRouterStatusService und BackupScheduler kommen auf Hintergrundfäden. Eine ObservableCollection von dort aus zu ändern wirft entweder oder beschädigt still die Anzeige.

// Aus einem Ereignis der Fachschicht heraus:
Dispatcher.UIThread.Post(() => Lines.Add(neu));

// Wenn ein Rückgabewert gebraucht wird:
await Dispatcher.UIThread.InvokeAsync(() => …);

Ein DispatcherTimer läuft dagegen bereits auf dem Oberflächenfaden — dort ist kein Wechsel nötig (siehe LogPageViewModel).

2.3 Avalonia 12, nicht 11

Praktisch alle Anleitungen im Netz sind für Avalonia 11 und lassen sich hier nicht übernehmen. Bekannte Unterschiede:

  • BindingPlugins ist nicht mehr öffentlich. Das übliche DisableAvaloniaDataAnnotationValidation() aus den 11er-Vorlagen entfällt ersatzlos — nicht nachbauen.
  • ShutdownMode voll qualifizieren: Avalonia.Controls.ShutdownMode.

Diese Fehler brechen den Build. Das ist gut — sie fallen sofort auf.


3. Das Muster

Der Logs-Bereich ist als vollständiges Beispiel gebaut. Drei Dateien, drei Aufgaben:

src/ClawdDotNet.App/Services/LogTail.cs — die Fachlogik. Liest Dateien, kennt keine Oberfläche, wäre ohne Fenster lauffähig.

src/ClawdDotNet.Desktop/ViewModels/LogPageViewModel.cs — das Ansichtsmodell. Erbt von PageViewModel, hält Zustand und Befehle. Kennt keine Steuerelemente.

src/ClawdDotNet.Desktop/Views/LogPageView.axaml — die Ansicht. Nur Aufbau und Bindungen.

Ein neuer Bereich in vier Schritten

1. Ansichtsmodell anlegen, von PageViewModel erbend:

public sealed partial class InfoPageViewModel : PageViewModel
{
    public InfoPageViewModel(AppHost? host) : base("Info") { … }
}

AppHost? ist nullbar — der Entwurfsmodus des Editors erzeugt das Ansichtsmodell ohne laufenden Aufbau. Bei null einfach nichts starten und Beispielwerte zeigen.

2. Ansicht anlegen: Views/InfoPageView.axaml + .axaml.cs. Der Name muss der Konvention folgen — ViewLocator sucht …ViewModels.FooViewModel → …Views.FooView. Passt der Name nicht, steht der gesuchte Typ im Fenster statt der Ansicht.

3. In MainWindowViewModel den Platzhalter ersetzen:

new PlaceholderPageViewModel("Info", "…")   // vorher
new InfoPageViewModel(host)                 // nachher

4. x:DataType in der AXAML setzen. Ohne das greifen die kompilierten Bindungen nicht und Tippfehler in Bindungspfaden fallen erst zur Laufzeit auf.

Werkzeugkasten

  • Zustand: [ObservableProperty] private string _text = ""; → erzeugt Text samt Benachrichtigung.
  • Befehle: [RelayCommand] private void Speichern() { … } → bindbar als SpeichernCommand.
  • Formatierung gehört in Styles/, nicht an einzelne Steuerelemente. Seit der Umsetzung des Entwurfs aus Mockup/ liegt sie in drei Dateien: Theme.axaml (Farben je Thema, Schriften), Icons.axaml (Symbolgeometrien), Shell.axaml (Steuerelement-Vorlagen und Stilklassen). Klassen: h1, h2, kicker, label, caption, muted, mono, card, console, hr, sep, toolbar, thead, tr, th, td, tag, statusbar, topbar, sidebar, nav; an Schaltflächen zusätzlich primary, toolbar, ghost, flat, icon.
  • Symbole über Controls/StrokeIcon.cs mit einer Geometrie aus Icons.axaml. Die Farbe wird geerbt — nicht gesetzt.
  • Rahmen mit Eckmarken über Controls/BlueprintFrame.cs. Sparsam: nur Dialoge und die Info-Karte.
  • Tabellen von Hand aus Border.thead + ListBox.table, nicht mit DataGrid. Das Paket ist nicht mehr referenziert.
  • Avalonia 12 hat die Ressourcenschlüssel des Fluent-Themas umgebaut. Die aus 11er-Anleitungen bekannten Namen (ButtonBackground, TextControlBackground, ControlCornerRadius …) existieren nicht mehr; ein Setter darauf ist wirkungslos und fällt nicht auf. Für neue Steuerelemente deshalb eine eigene ControlTheme in Shell.axaml schreiben statt zu versuchen, Fluent umzufärben.
  • Ordner öffnen: Core.Storage.SystemShell.OpenFolder(pfad). Kein explorer.exe.
  • Dateinamen erzeugen: Core.Storage.PortableFileName.Sanitize(name).

4. Prüfliste für die leisen Fehler

Diese Klasse bricht weder den Build noch die Tests. Vor jeder Abgabe durchgehen:

  • Fenster-Schließen behandelt? Wartet der Code auf eine Antwort aus einem Fenster (TaskCompletionSource), muss window.Closed als Abbruch gelten. Sonst hängt der Ablauf lautlos für immer.
  • Sammlungen nur vom Oberflächenfaden geändert? Siehe 2.2.
  • Wächst etwas unbegrenzt? Listen, die im Betrieb volllaufen, brauchen eine Obergrenze (LogPageViewModel.MaxLines = 2000 als Vorbild).
  • Timer beendet? DispatcherTimer in einem Ansichtsmodell läuft weiter, auch wenn der Bereich nicht sichtbar ist. Bei teuren Abfragen anhalten.
  • Farben aus dem Thema? Keine festen Farbwerte — die Anwendung läuft hell und dunkel. {DynamicResource …} verwenden.
  • Keine relativen Pfade. ./Backups und Ähnliches hängt vom Arbeitsverzeichnis ab und zeigt unter Linux ins Leere. AppPaths.DataDirectory verwenden.
  • Kein MessageBox, kein System.Windows.Forms, kein System.Drawing.

5. Abnahme

dotnet build ClawdDotNet.slnx
dotnet test tests/ClawdDotNet.Core.Tests/ClawdDotNet.Core.Tests.csproj

Beide müssen fehlerfrei sein — 567 Tests, keine neuen Fehlschläge.

Und dann tatsächlich starten. Die Oberfläche hat keine Testabdeckung; die Fehler aus Abschnitt 4 fallen ausschließlich beim Laufen auf.

dotnet run --project src/ClawdDotNet.Desktop

Hinweis: Ein Starttest hinterlässt unter Windows einen Prozess, der die .exe sperrt und den nächsten Build mit MSB3021 scheitern lässt. Aufräumen mit:

powershell -Command "Get-Process ClawdDotNet -EA SilentlyContinue | Stop-Process -Force"

6. Wenn etwas unklar ist

Lieber nachfragen als raten. Zwei Dinge sind besonders leicht falsch zu machen:

  • Was gehört in welche Schicht? Im Zweifel nach App — von dort kann die Oberfläche es holen, umgekehrt nicht.
  • Wie kommen Daten aus der Engine in die Ansicht? AppHost gibt Engine, Scanner, Staging, Status und Usage heraus; alle sind nullbar, wenn kein OpenRouter-Schlüssel hinterlegt ist. Diesen Fall mitdenken — die Anwendung läuft dann bewusst ohne Agenten.