Zum Inhalt
Kuonen.UI

ComboBox

Ein Klappfeld: zeigt die gewählte Möglichkeit, die Liste klappt darunter auf. Der Fokus bleibt im Feld; die Pfeile heben in der offenen Liste eine Stelle hervor, Eingabe übernimmt, Escape schliesst. Getippte Buchstaben springen zum passenden Eintrag. Editierbar (IsEditable) ist die Box ein Textfeld: Tippen ergänzt den ersten passenden Ort markiert und wählt ihn.

Vorführung: ComboBoxVorführung: ComboBox

KXAML

ComboBoxSeite.kxaml
<StackPanel xmlns="https://ui.kuonen.org/kxaml"
            xmlns:x="https://ui.kuonen.org/kxaml/x"
            xmlns:local="using:Kuonen.UI.Galerie.Seiten"
            x:Class="Kuonen.UI.Galerie.Seiten.ComboBoxVorfuehrung"
            Spacing="12">
  <TextBlock Text="Farbe" FontWeight="SemiBold" />
  <!-- Erst die Einträge, dann die Wahl, dann die Handler: der Startzustand meldet nichts. -->
  <ComboBox x:Name="Farbe" Width="180" ItemsSource="{x:Static local:ComboBoxVorfuehrung.Farben}" SelectedIndex="4"
            SelectionChanged="Farbe_SelectionChanged" DropDownOpened="Farbe_DropDownOpened" DropDownClosed="Farbe_DropDownClosed" />
  <Button Content="Liste öffnen" Click="Oeffnen_Click" />
  <TextBlock Text="10 000 Einträge, Liste höchstens 160 hoch" FontWeight="SemiBold" />
  <!-- Eine lange Liste: nur die sichtbaren Zeilen werden angelegt, die Höhe der Liste ist begrenzt. -->
  <ComboBox Width="180" ItemsSource="{x:Static local:ComboBoxVorfuehrung.Zahlen}" MaxDropDownHeight="160" SelectedIndex="0" />
  <TextBlock Text="Deaktiviert" FontWeight="SemiBold" />
  <ComboBox Width="180" ItemsSource="{x:Static local:ComboBoxVorfuehrung.Aus}" SelectedIndex="0" IsEnabled="False" />
  <TextBlock x:Name="Meldung" Text="Gewählt: Blau." />
  <TextBlock Text="Editierbar" FontWeight="SemiBold" />
  <!-- Editierbar: Tippen ergänzt den ersten passenden Ort markiert und wählt ihn; ohne Treffer bleibt der Text frei. -->
  <ComboBox x:Name="Ort" Width="180" IsEditable="True" PlaceholderText="Ort eingeben" ItemsSource="{x:Static local:ComboBoxVorfuehrung.Orte}"
            SelectionChanged="Ort_SelectionChanged" />
  <ToggleSwitch OffContent="Änderbar" OnContent="Nur lesen" Checked="NurLesen_Checked" Unchecked="NurLesen_Unchecked" />
  <TextBlock x:Name="Stand" Text="Text: „“, gewählt: nichts" />
</StackPanel>
ComboBoxSeite.kxaml.cs
using System.Globalization;
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Ereignisse;

namespace Kuonen.UI.Galerie.Seiten;

public sealed partial class ComboBoxSeite
{
    protected override Func<UIElement>? KxamlFabrik => () => new ComboBoxVorfuehrung();
}

/// <summary>KXAML-Fassung der ComboBox-Seite: der Baum steht in ComboBoxSeite.kxaml, hier die Daten und das Verhalten.</summary>
public sealed partial class ComboBoxVorfuehrung
{
    /// <summary>Die Einträge der Listen (im KXAML über x:Static).</summary>
    public static readonly string[] Farben = ["Rot", "Orange", "Gelb", "Grün", "Blau", "Violett"];

    public static readonly string[] Zahlen = BaueZahlen();

    public static readonly string[] Aus = ["Nicht bedienbar"];

    public static readonly string[] Orte = ["Basel", "Bern", "Biel", "Chur", "Genf", "Lausanne", "Lugano", "Luzern", "St. Gallen", "Winterthur", "Zürich"];

    public ComboBoxVorfuehrung()
    {
        InitializeComponent();
        Ort.Abonniere(ComboBox.TextProperty, (_, _, _) => Stand.Text = ComboBoxSeite.Stand(Ort));
    }

    private void Ort_SelectionChanged(object sender, SelectionChangedEventArgs e) => Stand.Text = ComboBoxSeite.Stand(Ort);

    private void NurLesen_Checked(object sender, RoutedEventArgs e) => Ort.IsReadOnly = true;

    private void NurLesen_Unchecked(object sender, RoutedEventArgs e) => Ort.IsReadOnly = false;

    private static string[] BaueZahlen()
    {
        var zahlen = new string[10_000];
        for (int i = 0; i < zahlen.Length; i++) zahlen[i] = $"Nummer {(i + 1).ToString("N0", CultureInfo.InvariantCulture)}";
        return zahlen;
    }

    private void ZeigeWahl() => Meldung.Text = Farbe.SelectedItem is { } wahl ? $"Gewählt: {wahl}." : "Nichts gewählt.";

    private void Farbe_SelectionChanged(object sender, SelectionChangedEventArgs e) => ZeigeWahl();

    private void Farbe_DropDownOpened(object? sender, EventArgs e) => Meldung.Text = "Die Liste ist offen.";

    private void Farbe_DropDownClosed(object? sender, EventArgs e) => ZeigeWahl();

    private void Oeffnen_Click(object sender, RoutedEventArgs e) => Farbe.IsDropDownOpen = true;
}

C#

ComboBoxSeite.cs
using System.Globalization;
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Layout;

namespace Kuonen.UI.Galerie.Seiten;

/// <summary>Galerie-Seite: <see cref="ComboBox"/>.</summary>
public sealed partial class ComboBoxSeite : GalerieSeite
{
    public override string Titel => "ComboBox";

    public override string Beschreibung =>
        "Ein Klappfeld: zeigt die gewählte Möglichkeit, die Liste klappt darunter auf. Der Fokus bleibt im Feld; die Pfeile "
        + "heben in der offenen Liste eine Stelle hervor, Eingabe übernimmt, Escape schliesst. Getippte Buchstaben springen "
        + "zum passenden Eintrag. Editierbar (IsEditable) ist die Box ein Textfeld: Tippen ergänzt den ersten passenden Ort markiert und wählt ihn.";

    public override string Stichworte => "Klappfeld Kombinationsfeld Dropdown Auswahl IsDropDownOpen SelectedItem MaxDropDownHeight editierbar IsEditable Ergänzung Text";

    internal static string Stand(ComboBox box) => $"Text: „{box.Text}“, gewählt: {box.SelectedItem ?? "nichts"}";

    public override string Datei => nameof(ComboBoxSeite);

    public override UIElement Baue()
    {
        var meldung = new TextBlock { Text = "Gewählt: Blau." };
        var farbe = new ComboBox { Width = 180, ItemsSource = new[] { "Rot", "Orange", "Gelb", "Grün", "Blau", "Violett" }, SelectedIndex = 4 };
        void ZeigeWahl() => meldung.Text = farbe.SelectedItem is { } wahl ? $"Gewählt: {wahl}." : "Nichts gewählt.";
        farbe.SelectionChanged += (_, _) => ZeigeWahl();
        farbe.DropDownOpened += (_, _) => meldung.Text = "Die Liste ist offen.";
        farbe.DropDownClosed += (_, _) => ZeigeWahl();

        // Eine lange Liste: nur die sichtbaren Zeilen werden angelegt, die Höhe der Liste ist begrenzt.
        var zahlen = new string[10_000];
        for (int i = 0; i < zahlen.Length; i++) zahlen[i] = $"Nummer {(i + 1).ToString("N0", CultureInfo.InvariantCulture)}";
        var viele = new ComboBox { Width = 180, ItemsSource = zahlen, MaxDropDownHeight = 160, SelectedIndex = 0 };

        var aus = new ComboBox { Width = 180, ItemsSource = new[] { "Nicht bedienbar" }, SelectedIndex = 0, IsEnabled = false };

        var oeffnen = new Button { Content = "Liste öffnen" };
        oeffnen.Click += (_, _) => farbe.IsDropDownOpen = true;

        var seite = new StackPanel { Spacing = 12 };
        seite.Children.Add(new TextBlock { Text = "Farbe", FontWeight = 600 });
        seite.Children.Add(farbe);
        seite.Children.Add(oeffnen);
        seite.Children.Add(new TextBlock { Text = "10 000 Einträge, Liste höchstens 160 hoch", FontWeight = 600 });
        seite.Children.Add(viele);
        seite.Children.Add(new TextBlock { Text = "Deaktiviert", FontWeight = 600 });
        seite.Children.Add(aus);
        seite.Children.Add(meldung);

        // Editierbar: Tippen ergänzt den ersten passenden Ort markiert und wählt ihn; ohne Treffer bleibt der Text frei.
        var ort = new ComboBox { Width = 180, IsEditable = true, PlaceholderText = "Ort eingeben", ItemsSource = ComboBoxVorfuehrung.Orte };
        var stand = new TextBlock { Text = "Text: „“, gewählt: nichts" };
        ort.Abonniere(ComboBox.TextProperty, (_, _, _) => stand.Text = Stand(ort));
        ort.SelectionChanged += (_, _) => stand.Text = Stand(ort);
        var nurLesen = new ToggleSwitch { OffContent = "Änderbar", OnContent = "Nur lesen" };
        nurLesen.Checked += (_, _) => ort.IsReadOnly = true;
        nurLesen.Unchecked += (_, _) => ort.IsReadOnly = false;
        seite.Children.Add(new TextBlock { Text = "Editierbar", FontWeight = 600 });
        seite.Children.Add(ort);
        seite.Children.Add(nurLesen);
        seite.Children.Add(stand);
        return seite;
    }
}