Zum Inhalt
Kuonen.UI

KXAML-Designer

Live-Vorschau in VS Code, Controls ablegen, Ereignisse anlegen, Sicherheit.

Der Designer zeigt eine .kxaml-Datei neben dem Editor als Live-Vorschau, gezeichnet vom echten Renderer von Kuonen.UI. Ein Klick in die Vorschau setzt den Cursor in das öffnende Tag des Elements, ein Doppelklick legt den Handler des primären Ereignisses an (Attribut im KXAML, Methode im Code-Behind), und aus der Werkzeugkiste lassen sich Elemente in die Vorschau ziehen. Bearbeitet wird immer das XML; die Vorschau folgt jeder Änderung.

Bedienung

  • Öffnen: Befehl „Kuonen KXAML: Designer öffnen“ oder das Symbol in der Titelleiste einer .kxaml. Beim ersten Mal fragt die Erweiterung, ob die Vorschau Code des Projekts ausführen darf (siehe Sicherheit); die Antwort gilt für den Arbeitsbereich und lässt sich bisher nicht zurücknehmen (kein Befehl dafür; der Schlüssel kuonenKxaml.vorschauErlaubt liegt im Arbeitsbereichsspeicher von VS Code).
  • Klick: wählt das innerste Element unter dem Zeiger, rahmt es in der Vorschau ein und setzt den Cursor auf seinen Namen im öffnenden Tag. Teile einer Vorlage (ControlTemplate, DataTemplate) gehören zum Control, das sie benutzt; ein Panel ohne Hintergrund ist trotzdem wählbar.
  • Doppelklick: das primäre Ereignis des Elements ([DefaultEvent], wie in WPF: Button → Click, CheckBox → Checked, TextBox → TextChanged, ListBox/ComboBox/TreeView/DataGrid → SelectionChanged, Slider → ValueChanged, HyperlinkButton → Click, LinkLabel → LinkClicked, GridSplitter → DragDelta, SplitContainer → SplitterMoved, Calendar → SelectedDatesChanged, MonthCalendar → DateChanged, DatePicker → SelectedDateChanged, TimePicker → SelectedTimeChanged, DateTimePicker → ValueChanged …) bekommt den Handler Name_Ereignis (nach x:Name, sonst nach dem Typ; belegte Namen mit _2, _3, …). Attribut und Methode kommen in einer Bearbeitung (eine Rückgängig-Stufe); die C#-Datei wird gespeichert, damit der Sprachserver die Methode sieht, und der Cursor steht im leeren Rumpf. Ist das Ereignis schon verdrahtet, springt der Cursor zum Handler. Hat die C#-Datei ungespeicherte Änderungen, ändert der Designer nichts und bittet ums Speichern.
  • Ziehen aus der Werkzeugkiste: die Liste links enthält die Elemente von Kuonen.UI und die eigenen des Projekts (abgeleitet von UIElement, mit öffentlichem parameterlosem Konstruktor, kein Window). Abgelegt wird im innersten Element unter dem Zeiger, das es aufnimmt: in Panels und anderen Sammlungen als letztes Kind, in einen Einzelinhalt (Border, ContentControl) nur, wenn er noch leer ist; im Canvas mit Canvas.Left/Canvas.Top. Die Einrückung folgt den Einstellungen des Editors, die Zeilenwechsel dem Dokument; fehlt für einen Typ des Projekts der Präfix, wird xmlns:local="using:…" an der Wurzel erklärt. Ein Typ kann mit [AblageVorgabe("…")] die Attribute bestimmen, die beim Ablegen statt Content=/Text= eingesetzt werden (Formen mit Grösse und Füllung, UniformGrid mit Rows und Columns, Viewbox, SplitContainer). Seit Welle 6b stehen die sechs Formen (Kuonen.UI.Shapes), UniformGrid, RelativePanel, UserControl, Viewbox, LayoutTransformControl, GridSplitter, SplitContainer, HyperlinkButton und LinkLabel in der Werkzeugkiste (Test Neue_Elemente_der_Welle_6b_stehen_in_der_Werkzeugkiste); DispatcherTimer, MessageBox und TaskDialog sind keine Elemente und fehlen dort. Seit Welle 6c kommen Calendar, MonthCalendar, DatePicker, CalendarDatePicker, TimePicker und DateTimePicker dazu (Test Neue_Elemente_der_Welle_6c_stehen_in_der_Werkzeugkiste); die Tagesknöpfe CalendarDayButton und CalendarButton legt der Kalender selbst an, sie fehlen dort. Seit Welle 6d stehen SelectableTextBlock, MaskedTextBox, AutoCompleteBox, SearchBox, SplitButton, ToggleSplitButton, DropDownButton, Chip, ChipGroup, SegmentedControl, SegmentedControlItem, ButtonSpinner, DomainUpDown, RangeSlider, RatingBar, ColorSpectrum, ColorSlider, ColorView und ColorPicker dort (Test Neue_Elemente_der_Welle_6d_stehen_in_der_Werkzeugkiste); abgelegt bekommen ColorPicker und ColorView Color="#0078D4", RangeSlider Breite und beide Werte, RatingBar drei Sterne, SearchBox eine Breite, SplitButton und DropDownButton einen Inhalt. Die Bausteine Spinner, Klappteil und Vorschlagsliste fehlen dort.
  • Bedienen: mit dem Schalter „Bedienen“ gehen Zeiger, Rad und Tastatur an die Vorschau (Hover, Drücken, Handler laufen); der Text ändert sich dabei nicht. Animationen laufen in simulierter Zeit bis zur Ruhe.
  • Dunkel: zeigt die Seite im dunklen Fluent-Theme, sofern die Wurzel selbst keins setzt.
  • Umgebung: zeigt die Seite, wie sie auf einer Plattform erscheint (Plan U): Windows (Fluent, Segoe UI), Linux mit GNOME (Adwaita, Cantarell) oder KDE (Breeze, Noto Sans), macOS (SF Pro Text), Android (Material, Roboto) und iOS (SF Pro Text) mit sicherer Zone und Bildschirmtastatur, dazu der Browser. Telefone erscheinen in ihrer typischen Grösse (Android 412 × 915, iOS 390 × 844), die übrigen in der Fläche der Vorschau; „Standard“ zeigt die Seite wie bisher. Fehlt eine Schrift auf dem Rechner, greift der Rückfall der Schriftbibliothek. Die Wahl gilt je Dokument und bleibt im Arbeitsbereich gemerkt; eine Wurzel mit eigenem Theme behält es. Die Seite erfährt die Umgebung über dieselben Wege wie auf dem Gerät (Theme, Einzüge, Höhe der Bildschirmtastatur), siehe docs/app.md.
  • Halb getipptes KXAML: Lässt sich der Text gerade nicht zeigen (nicht wohlgeformt, Meldungen des Generators, C#-Fehler, Ausnahme im Konstruktor), bleibt das letzte Bild stehen; der Balken unten sagt, warum (Zustand veraltet). Klicks werden dann abgewiesen, statt an eine falsche Stelle zu springen. Verwirft das Webview ein Teilbild, fordert es ein ganzes an.

Aufbau

VS Code ── Webview (designer/vorschau.js, Leinwand, Werkzeugkiste)
   │ postMessage (geprüft: designer/vorschau-logik.js)
   ▼
designer.js ── LSP kxaml/vorschau/* ──► Sprachserver ── Rahmen über stdin/stdout ──► Vorschauprozess
                                           │ VorschauBau: Compilation des Projekts       │ sammelbarer Ladekontext
                                           │ + erzeugter Code aller KXAML-Dateien         │ HeadlessHost, Fensterbindung
                                           │   (die gezeigte mit Herkunftsmarken)          │ Kacheln als PNG
                                           │ + Herkunft + Einstieg → Emit (Bytes)          │ Treffer, Eingaben
  • Sprachserver (tools/Kuonen.UI.Kxaml.Sprachserver/Vorschau): baut die Assembly mit Roslyn im Speicher (VorschauBau), lädt sie nie selbst und bleibt so AOT-tauglich. Der Generator übersetzt die gezeigte Datei im Vorschau-Modus: nach jedem Element ausserhalb von Vorlagen steht KuonenVorschau.Herkunft.Merke(element, zeile, spalte). Der Einstieg (VorschauEinstieg) meldet über AppContext eine Fabrik für die x:Class und die Abfrage der Herkunft – der Vorschauprozess braucht dafür keine Reflexion.
  • Vorschauprozess (tools/Kuonen.UI.Designer.Vorschau): ein eigener Prozess je Vorschau. Er lädt die Assembly in einen sammelbaren AssemblyLoadContext; Abhängigkeiten des Projekts kommen aus den Laufzeitpfaden von MSBuild (ReferenceCopyLocalPaths, sonst die Implementierungen der Referenzen) und werden aus dem Speicher geladen (keine Dateisperre, der nächste Bau darf sie überschreiben). Kuonen.UI selbst und die BCL kommen aus dem Prozess: die Vorschau zeichnet mit ihrem eigenen Kuonen.UI (verlangt das Projekt eine neuere Fassung, steht ein Hinweis im Balken). Die Wurzel wird im HeadlessHost gezeigt (ein Window über Show, sonst eine Fensterbindung).
  • Teilaktualisierung: der Vorschauprozess vergleicht jedes Bild in Kacheln zu 64 Pixeln mit dem zuletzt gesendeten und schickt nur geänderte Bereiche (je Kachelzeile zusammengefasst, höchstens 64, sonst einer um alle) als PNG. Eine neue Fassung gleicher Grösse schickt so nur, was sich geändert hat; ein neues Webview oder eine neue Grösse bekommt das ganze Bild.
  • Inkrementell und gezählt: nach einer Änderung prüft der Leerlauf des Servers nur die betroffenen Vorschauen; gleiche Eingaben übersetzen und laden nicht neu (VorschauBau.Uebersetzungen, Emits; VorschauZaehler.Ladevorgaenge, Pruefungen). Abfragen ohne Änderung prüfen nichts.
  • Methoden: kxaml/vorschau/oeffnen, groesse, bild, treffer, werkzeugkiste, ablegen, ereignis, eingabe, schliessen; Bilder kommen im Leerlauf zusätzlich als Benachrichtigung kxaml/vorschau/bild. Der Server hält höchstens 16 Vorschauen offen.

Sicherheit

  • Code des Projekts läuft: Konstruktoren der Seite und ihrer Controls, Handler im Bedienen-Modus. Darum gilt:
    • Vertrauter Arbeitsbereich: in einem nicht vertrauten ist die ganze Erweiterung aus (untrustedWorkspaces.supported: false); designer.js prüft zusätzlich isTrusted.
    • Zustimmung: beim ersten Öffnen je Arbeitsbereich eine modale Rückfrage; erst danach schickt die Erweiterung kxaml/vorschau/oeffnen mit zugestimmt: true, ohne dieses Feld nimmt der Server die Anfrage nicht an.
    • Der Server lädt keinen Projektcode: er übersetzt nur Bytes (Roslyn im Speicher). Der übersetzte Code der Projekt-Assembly (Konstruktoren, Handler) wird ausschliesslich im Vorschauprozess ausgeführt. Davon unabhängig führt der Server schon für IntelliSense dotnet msbuild auf das Projekt aus (siehe docs/sprachserver.md); dabei läuft Code des Projekts in MSBuild-Zielen, auch ohne Zustimmung zum Designer.
  • Eigener Prozess, begrenzt:
    • ein Prozess je Vorschau, ohne Fenster, Arbeitsordner ist der Ordner des Vorschauprozesses (nie der des Arbeitsbereichs);
    • Speicher: GC-Heap höchstens 1 GiB (DOTNET_GCHeapHardLimit, Workstation-GC);
    • Fristen: Antwortfrist 10 s, ebenso beim Schreiben und beim Abschied (ende); ein hängender Konstruktor beendet den Prozess samt Kindern, die Vorschau meldet es und startet beim nächsten Bedarf neu;
    • Grössen: höchstens 4096 Gerätepixel je Seite, Skalierung 0,5 bis 4 (NaN und ∞ werden abgewiesen); Rahmen höchstens 1 MiB Kopf und 128 MiB Daten; Abhängigkeiten höchstens 4096 Stück und zusammen 512 MiB; stderr als Ringpuffer von 64 KiB (für Meldungen bleiben 4096 Zeichen).
  • Gezielte Umgebung: der Vorschauprozess erbt nicht die Umgebung des Servers, sondern nur diese Liste: PATH, SystemRoot, windir, SystemDrive, ComSpec, TEMP, TMP, TMPDIR, HOME, USERPROFILE, LOCALAPPDATA, APPDATA, ProgramFiles, ProgramFiles(x86), ProgramW6432, ProgramData, NUMBER_OF_PROCESSORS, PROCESSOR_ARCHITECTURE, OS, DOTNET_ROOT, DOTNET_ROOT_X64, DOTNET_ROOT_X86, DOTNET_ROOT_ARM64, DOTNET_MULTILEVEL_LOOKUP, LANG, LC_ALL, XDG_RUNTIME_DIR. Dazu setzt der Server DOTNET_GCHeapHardLimit, DOTNET_gcServer=0 und DOTNET_CLI_TELEMETRY_OPTOUT=1. Nicht dabei sind Proxy-Einstellungen, Zertifikatspfade, USERNAME und alles, was nach Zugangsdaten aussieht (ebenso DOTNET_STARTUP_HOOKS und COMPlus_*). Projektcode, der das Netz braucht, findet also keinen Proxy und keine eigenen Zertifikate; Windows-Funktionen, die USERNAME lesen, sehen den Wert nicht.
  • stdout gehört dem Protokoll: der Vorschauprozess öffnet stdout für die Rahmen und leitet Console.Out auf stderr um; was der Projektcode mit Console.WriteLine schreibt, landet dort. Öffnet Projektcode Console.OpenStandardOutput() selbst und schreibt hinein, zerstört er das Protokoll; der Server erkennt den Protokollfehler, beendet den Prozess und startet bei Bedarf einen neuen.
  • Webview: nur eigene Dateien (localResourceRoots ist der Ordner designer/), Inhaltsrichtlinie default-src 'none', Skripte nur mit einer Nonce je Seite (128 Bit), Stile nur aus dem Ordner der Erweiterung, Bilder nur als blob:, connect-src/frame-src/form-action 'none', base-uri 'none'; keine Formulare, keine Befehls-URIs (enableCommandUris: false). Ungültige Angaben ergeben eine Seite ohne Skripte.
  • Nachrichtenprüfung: jede Nachricht des Webviews wird in designer/vorschau-logik.js geprüft (bekannte Art, Typen, Wertebereiche, Längen); Unbekanntes wird verworfen, je Webview warten höchstens 64 Nachrichten. Weil diese Prüfung die Werkzeugliste nicht kennt, legt designer.js nur einen Typ ab, der in der Werkzeugkiste dieses Dokuments steht (der Server nimmt ohnehin nur ablegbare Typen an).
  • Nur file:-Adressen: Der Designer öffnet nur Dokumente mit dem Schema file; Bearbeitungen des Servers werden nur auf Dateien auf der Platte angewandt, jede andere Adresse wird übergangen.
  • Versionsprüfung vor applyEdit: ändert sich der Text des Dokuments, während der Server die Bearbeitung berechnet, passen die Stellen nicht mehr: designer.js vergleicht die Dokumentversion vor und nach der Anfrage, verwirft die Antwort und fragt einmal neu; danach gibt es einen Hinweis statt einer falschen Bearbeitung. Für die C#-Datei gilt das nicht (siehe Grenzen).

Lizenz

In der lizenzierten Ausgabe (docs/lizenz.md) braucht der Designer das Merkmal Werkzeuge.Designer, Vervollständigung, Hover, Gehe zu Definition, Umbenennen, Formatieren und Färbung brauchen Werkzeuge.Sprachdienste; die Meldungen zum KXAML bleiben immer (sie kommen auch beim Bauen). Der Schlüssel kommt aus einer Datei *.kuonenlizenz im Projekt (dieselbe, die der Generator in die Anwendung bringt) oder aus der Einstellung kuonenKxaml.lizenz (nur in den Benutzereinstellungen). Ohne Lizenz öffnet die Vorschau nicht, und die Sprachdienste bleiben mit einem einmaligen Hinweis leer. Die Vorschau meldet die Lizenzdateien des Projekts selbst an, damit lizenzierte Controls dort ohne Hinweis erscheinen, wie in der Anwendung. In der freien Ausgabe ist alles frei.

Grenzen

  • Statische Abos und Neustarts: statische Ereignisabos oder Threads des Projektcodes halten alte Ladekontexte fest. Darum startet nach 50 Fassungen (MaxLadevorgaengeJeProzess) ein frischer Prozess; bis dahin kann der Speicher wachsen, und jedes Wieder-Einblenden eines Webviews lädt neu und zählt mit. Ein abgestürzter oder hängender Prozess wird beim nächsten Bedarf ersetzt, höchstens fünfmal je Vorschau (danach erst nach erneutem Öffnen).
  • C# und Doppelklick: der Server sieht C# erst nach dem Speichern. Ist die C#-Datei gespeichert, dem Server aber noch nicht gemeldet, kann die Methode an veralteter Stelle landen (die Versionsprüfung deckt nur das KXAML-Dokument ab).
  • Zustimmung lässt sich nicht zurücknehmen (kein Befehl); nur das Löschen des Arbeitsbereichsspeichers in VS Code setzt sie zurück.
  • Nicht im Umfang: weitere Quellgeneratoren des Projekts (ihr Code fehlt in der Vorschau-Compilation; die Vorschau meldet dann C#-Fehler), eingebettete Ressourcen des Projekts, ungespeicherte C#-Puffer, Auswahl im Text → Rahmen in der Vorschau, Verschieben und Grössenziehen in der Vorschau, Grid-Zellen als Ziel, Vorschau von Wörterbüchern, Zoom. Die Vorschau zeichnet mit ihrem eigenen Kuonen.UI, nicht mit der Fassung des Projekts.
  • Rechner: die Fristen sind absolute Zeiten; unter sehr hoher Last kann die Vorschau in die 10-s-Frist laufen und neu starten.