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üsselkuonenKxaml.vorschauErlaubtliegt 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 HandlerName_Ereignis(nachx: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, keinWindow). 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 mitCanvas.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, wirdxmlns:local="using:…"an der Wurzel erklärt. Ein Typ kann mit[AblageVorgabe("…")]die Attribute bestimmen, die beim Ablegen stattContent=/Text=eingesetzt werden (Formen mit Grösse und Füllung,UniformGridmitRowsundColumns,Viewbox,SplitContainer). Seit Welle 6b stehen die sechs Formen (Kuonen.UI.Shapes),UniformGrid,RelativePanel,UserControl,Viewbox,LayoutTransformControl,GridSplitter,SplitContainer,HyperlinkButtonundLinkLabelin der Werkzeugkiste (TestNeue_Elemente_der_Welle_6b_stehen_in_der_Werkzeugkiste);DispatcherTimer,MessageBoxundTaskDialogsind keine Elemente und fehlen dort. Seit Welle 6c kommenCalendar,MonthCalendar,DatePicker,CalendarDatePicker,TimePickerundDateTimePickerdazu (TestNeue_Elemente_der_Welle_6c_stehen_in_der_Werkzeugkiste); die TagesknöpfeCalendarDayButtonundCalendarButtonlegt der Kalender selbst an, sie fehlen dort. Seit Welle 6d stehenSelectableTextBlock,MaskedTextBox,AutoCompleteBox,SearchBox,SplitButton,ToggleSplitButton,DropDownButton,Chip,ChipGroup,SegmentedControl,SegmentedControlItem,ButtonSpinner,DomainUpDown,RangeSlider,RatingBar,ColorSpectrum,ColorSlider,ColorViewundColorPickerdort (TestNeue_Elemente_der_Welle_6d_stehen_in_der_Werkzeugkiste); abgelegt bekommenColorPickerundColorViewColor="#0078D4",RangeSliderBreite und beide Werte,RatingBardrei Sterne,SearchBoxeine Breite,SplitButtonundDropDownButtoneinen Inhalt. Die BausteineSpinner,KlappteilundVorschlagslistefehlen 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 stehtKuonenVorschau.Herkunft.Merke(element, zeile, spalte). Der Einstieg (VorschauEinstieg) meldet überAppContexteine 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 sammelbarenAssemblyLoadContext; 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 imHeadlessHostgezeigt (einWindowüberShow, sonst eineFensterbindung). - 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 Benachrichtigungkxaml/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.jsprüft zusätzlichisTrusted. - Zustimmung: beim ersten Öffnen je Arbeitsbereich eine modale Rückfrage; erst danach schickt die Erweiterung
kxaml/vorschau/oeffnenmitzugestimmt: 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 msbuildauf das Projekt aus (siehedocs/sprachserver.md); dabei läuft Code des Projekts in MSBuild-Zielen, auch ohne Zustimmung zum Designer.
- Vertrauter Arbeitsbereich: in einem nicht vertrauten ist die ganze Erweiterung aus (
- 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 ServerDOTNET_GCHeapHardLimit,DOTNET_gcServer=0undDOTNET_CLI_TELEMETRY_OPTOUT=1. Nicht dabei sind Proxy-Einstellungen, Zertifikatspfade,USERNAMEund alles, was nach Zugangsdaten aussieht (ebensoDOTNET_STARTUP_HOOKSundCOMPlus_*). Projektcode, der das Netz braucht, findet also keinen Proxy und keine eigenen Zertifikate; Windows-Funktionen, dieUSERNAMElesen, sehen den Wert nicht. - stdout gehört dem Protokoll: der Vorschauprozess öffnet stdout für die Rahmen und leitet
Console.Outauf stderr um; was der Projektcode mitConsole.WriteLineschreibt, landet dort. Öffnet ProjektcodeConsole.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 (
localResourceRootsist der Ordnerdesigner/), Inhaltsrichtliniedefault-src 'none', Skripte nur mit einer Nonce je Seite (128 Bit), Stile nur aus dem Ordner der Erweiterung, Bilder nur alsblob:,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.jsgeprü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, legtdesigner.jsnur 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 Schemafile; 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.jsvergleicht 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.