Code-Editor
Ein Editor für Abfragen wie in SSMS: Hervorhebung je Dialekt, Zeilennummern, Faltung (Strg+M Strg+M), Vorschläge (Strg+Leertaste) und Parameterhilfe, Suchen und Ersetzen (Strg+F, Strg+H), Gehe zu Zeile (Strg+G), Kommentar (Strg+K Strg+C), Spaltenauswahl (Alt+Ziehen). „Prüfen“ setzt Beispieldiagnosen: Wellenlinien mit Kurzinfo, F8 springt zur nächsten.


KXAML
CodeEditorSeite.kxaml
<StackPanel xmlns="https://ui.kuonen.org/kxaml"
xmlns:x="https://ui.kuonen.org/kxaml/x"
x:Class="Kuonen.UI.Galerie.Seiten.CodeEditorVorfuehrung"
Spacing="8">
<StackPanel Orientation="Horizontal" Spacing="8">
<ComboBox x:Name="Dialekt" MinWidth="130" />
<CheckBox x:Name="Nummern" Content="Zeilennummern" />
<Button x:Name="Pruefen" Content="Prüfen" />
<TextBlock x:Name="Lage" Text="Zeile 1, Spalte 1" VerticalAlignment="Center" />
</StackPanel>
<CodeEditor x:Name="Editor" Height="320" Language="{x:Static SqlSprache.TSql}" />
</StackPanel>CodeEditorSeite.kxaml.cs
using Kuonen.UI;
namespace Kuonen.UI.Galerie.Seiten;
public sealed partial class CodeEditorSeite
{
protected override Func<UIElement>? KxamlFabrik => () => new CodeEditorVorfuehrung();
}
/// <summary>KXAML-Fassung der Seite Code-Editor: der Aufbau steht in CodeEditorSeite.kxaml, hier das Verhalten.</summary>
public sealed partial class CodeEditorVorfuehrung
{
public CodeEditorVorfuehrung()
{
InitializeComponent();
CodeEditorSeite.Verdrahte(Editor, Dialekt, Nummern, Pruefen, Lage);
}
}C#
CodeEditorSeite.cs
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Layout;
namespace Kuonen.UI.Galerie.Seiten;
/// <summary>Galerie-Seite: der Code-Editor (<see cref="CodeEditor"/>) mit SQL in vier Dialekten.</summary>
public sealed partial class CodeEditorSeite : GalerieSeite
{
public override string Titel => "Code-Editor";
public override string Beschreibung =>
"Ein Editor für Abfragen wie in SSMS: Hervorhebung je Dialekt, Zeilennummern, Faltung (Strg+M Strg+M), Vorschläge (Strg+Leertaste) und "
+ "Parameterhilfe, Suchen und Ersetzen (Strg+F, Strg+H), Gehe zu Zeile (Strg+G), Kommentar (Strg+K Strg+C), Spaltenauswahl (Alt+Ziehen). "
+ "„Prüfen“ setzt Beispieldiagnosen: Wellenlinien mit Kurzinfo, F8 springt zur nächsten.";
public override string Stichworte =>
"CodeEditor AvalonEdit Monaco Scintilla SQL T-SQL PostgreSQL MySQL SQLite Syntax Hervorhebung Faltung IntelliSense Vorschläge Suchen Ersetzen Diagnosen Wellenlinie Spaltenauswahl";
public override string Datei => nameof(CodeEditorSeite);
/// <summary>Das Beispielskript der Seite.</summary>
public const string Beispiel = """
-- Umsatz je Kunde im laufenden Jahr
SELECT k.Name, SUM(r.Betrag) AS Umsatz
FORM dbo.Kunden AS k
JOIN dbo.Rechnungen AS r ON r.KundeId = k.Id
WHERE r.Datum >= DATEFROMPARTS(YEAR(GETDATE()), 1, 1)
GROUP BY k.Name
ORDER BY Umsatz DESC;
BEGIN
SELECT * FROM dbo.Kunden WHERE Ort = N'Bern';
END
""";
internal static readonly string[] Dialekte = ["T-SQL", "PostgreSQL", "MySQL", "SQLite"];
/// <summary>Das Verhalten beider Fassungen: Dialekt wählen, Zeilennummern schalten, Beispieldiagnosen setzen, Caret-Lage melden.</summary>
internal static void Verdrahte(CodeEditor editor, ComboBox dialekt, CheckBox nummern, Button pruefen, TextBlock lage)
{
editor.Text = Beispiel;
editor.Language = SqlSprache.TSql;
dialekt.ItemsSource = Dialekte;
dialekt.SelectedIndex = 0;
dialekt.SelectionChanged += (_, _) => editor.Language = dialekt.SelectedIndex switch
{
1 => SqlSprache.PostgreSql,
2 => SqlSprache.MySql,
3 => SqlSprache.Sqlite,
_ => SqlSprache.TSql,
};
nummern.IsChecked = true;
nummern.Checked += (_, _) => editor.ShowLineNumbers = true;
nummern.Unchecked += (_, _) => editor.ShowLineNumbers = false;
pruefen.Click += (_, _) =>
{
editor.Diagnostics = Pruefe(editor.Text);
lage.Text = $"{editor.Diagnostics.Count} Diagnosen. F8: zur nächsten.";
};
editor.SelectionChanged += (_, _) => lage.Text = $"Zeile {editor.CaretLine + 1}, Spalte {editor.CaretColumn + 1}";
}
// Beispieldiagnosen: „FORM“ statt FROM ist ein Fehler, „SELECT *“ eine Warnung.
internal static List<CodeDiagnose> Pruefe(string text)
{
var liste = new List<CodeDiagnose>();
for (int i = text.IndexOf("FORM", StringComparison.Ordinal); i >= 0; i = text.IndexOf("FORM", i + 1, StringComparison.Ordinal))
liste.Add(new CodeDiagnose(i, 4, CodeSchwere.Fehler, "Falsche Syntax bei „FORM“. Gemeint ist wohl FROM."));
for (int i = text.IndexOf("SELECT *", StringComparison.Ordinal); i >= 0; i = text.IndexOf("SELECT *", i + 1, StringComparison.Ordinal))
liste.Add(new CodeDiagnose(i + 7, 1, CodeSchwere.Warnung, "Spalten besser ausdrücklich nennen."));
return liste;
}
public override UIElement Baue()
{
var editor = new CodeEditor { Height = 320 };
var dialekt = new ComboBox { MinWidth = 130 };
var nummern = new CheckBox { Content = "Zeilennummern" };
var pruefen = new Button { Content = "Prüfen" };
var lage = new TextBlock { Text = "Zeile 1, Spalte 1", VerticalAlignment = VerticalAlignment.Center };
Verdrahte(editor, dialekt, nummern, pruefen, lage);
var leiste = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8, Children = { dialekt, nummern, pruefen, lage } };
return new StackPanel { Spacing = 8, Children = { leiste, editor } };
}
}