Zum Inhalt
Kuonen.UI

Popup

Ein Inhalt über allem anderen im Fenster, an ein Ziel gelegt (unten, oben, rechts, links, mittig). Passt er nicht, klappt er um. Mit StaysOpen = false schliesst ein Klick daneben oder Escape; der Fokus kehrt zurück.

Vorführung: PopupVorführung: Popup

KXAML

PopupSeite.kxaml
<StackPanel xmlns="https://ui.kuonen.org/kxaml"
            xmlns:x="https://ui.kuonen.org/kxaml/x"
            x:Class="Kuonen.UI.Galerie.Seiten.PopupVorfuehrung"
            Spacing="12">
  <!-- Lage wählen. -->
  <StackPanel Orientation="Horizontal" Spacing="12">
    <RadioButton Content="Unten" GroupName="PopupLage" IsChecked="True" Checked="Lage_Checked" />
    <RadioButton Content="Oben" GroupName="PopupLage" IsChecked="False" Checked="Lage_Checked" />
    <RadioButton Content="Rechts" GroupName="PopupLage" IsChecked="False" Checked="Lage_Checked" />
    <RadioButton Content="Links" GroupName="PopupLage" IsChecked="False" Checked="Lage_Checked" />
    <RadioButton Content="Mittig" GroupName="PopupLage" IsChecked="False" Checked="Lage_Checked" />
  </StackPanel>
  <!-- Bleibt offen: schliesst nur über die Schaltfläche. -->
  <CheckBox x:Name="Bleibt" Content="StaysOpen (schliesst nicht bei Klick daneben)" Click="Bleibt_Click" />
  <StackPanel Orientation="Horizontal" Spacing="16" Margin="160,40,0,40">
    <Button x:Name="Oeffner" Content="Popup öffnen" Click="Oeffner_Click" />
    <!-- PlacementTarget verweist mit x:Reference auf die Schaltfläche. -->
    <Popup x:Name="Fenster" PlacementTarget="{x:Reference Oeffner}" Placement="Bottom" VerticalOffset="4" StaysOpen="False" Opened="Popup_Opened" Closed="Popup_Closed">
      <!-- Der Inhalt: ein Rahmen in den QuickInfo-Farben des Themes (DynamicResource folgt dem Theme) mit zwei Kästchen. -->
      <Border CornerRadius="8" BorderThickness="1">
        <Border.Style>
          <Style TargetType="Border">
            <Setter Property="Background" Value="{DynamicResource Fluent.Farben.ToolTipFlaeche}" />
            <Setter Property="BorderBrush" Value="{DynamicResource Fluent.Farben.ToolTipRand}" />
          </Style>
        </Border.Style>
        <StackPanel Spacing="6" Margin="12">
          <TextBlock Text="Optionen" FontWeight="SemiBold" />
          <CheckBox Content="Rechtschreibung prüfen" />
          <CheckBox Content="Automatisch speichern" IsChecked="True" />
          <Button Content="Schliessen" Click="Schliessen_Click" />
        </StackPanel>
      </Border>
    </Popup>
  </StackPanel>
  <TextBlock x:Name="Meldung" Text="Geschlossen." />
</StackPanel>
PopupSeite.kxaml.cs
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Ereignisse;

namespace Kuonen.UI.Galerie.Seiten;

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

/// <summary>KXAML-Fassung der Popup-Seite: der Baum steht in PopupSeite.kxaml, hier nur das Verhalten.</summary>
public sealed partial class PopupVorfuehrung
{
    public PopupVorfuehrung() => InitializeComponent();

    private void Lage_Checked(object sender, RoutedEventArgs e) => Fenster.Placement = (string?)((RadioButton)sender).Content switch
    {
        "Oben" => PlacementMode.Top,
        "Rechts" => PlacementMode.Right,
        "Links" => PlacementMode.Left,
        "Mittig" => PlacementMode.Center,
        _ => PlacementMode.Bottom,
    };

    private void Bleibt_Click(object sender, RoutedEventArgs e) => Fenster.StaysOpen = Bleibt.IsChecked == true;

    private void Oeffner_Click(object sender, RoutedEventArgs e) => Fenster.IsOpen = !Fenster.IsOpen;

    private void Schliessen_Click(object sender, RoutedEventArgs e) => Fenster.IsOpen = false;

    private void Popup_Opened(object? sender, EventArgs e) => Meldung.Text = "Offen (Klick daneben oder Escape schliesst).";

    private void Popup_Closed(object? sender, EventArgs e) => Meldung.Text = "Geschlossen.";
}

C#

PopupSeite.cs
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Layout;
using Kuonen.UI.Themes;

namespace Kuonen.UI.Galerie.Seiten;

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

    public override string Beschreibung =>
        "Ein Inhalt über allem anderen im Fenster, an ein Ziel gelegt (unten, oben, rechts, links, mittig). Passt er "
        + "nicht, klappt er um. Mit StaysOpen = false schliesst ein Klick daneben oder Escape; der Fokus kehrt zurück.";

    public override string Stichworte => "Overlay Aufklapper Flyout Placement PlacementTarget StaysOpen leichtes Schliessen IsOpen";

    public override string Datei => nameof(PopupSeite);

    public override UIElement Baue()
    {
        var meldung = new TextBlock { Text = "Geschlossen." };
        var oeffner = new Button { Content = "Popup öffnen" };

        // Der Inhalt des Popups: ein Rahmen in den QuickInfo-Farben des Themes mit zwei Kästchen.
        var inhalt = new StackPanel { Spacing = 6, Margin = new Thickness(12) };
        inhalt.Children.Add(new TextBlock { Text = "Optionen", FontWeight = 600 });
        inhalt.Children.Add(new CheckBox { Content = "Rechtschreibung prüfen" });
        inhalt.Children.Add(new CheckBox { Content = "Automatisch speichern", IsChecked = true });
        var schliessen = new Button { Content = "Schliessen" };
        inhalt.Children.Add(schliessen);
        var rahmen = new Border
        {
            CornerRadius = new CornerRadius(8), BorderThickness = new Thickness(1), Child = inhalt,
            Style = new Style(typeof(Border))
                .Setze(Border.BackgroundProperty, Fluent.Farben.ToolTipFlaeche)
                .Setze(Border.BorderBrushProperty, Fluent.Farben.ToolTipRand),
        };
        var popup = new Popup { PlacementTarget = oeffner, Placement = PlacementMode.Bottom, VerticalOffset = 4, StaysOpen = false, Child = rahmen };
        popup.Opened += (_, _) => meldung.Text = "Offen (Klick daneben oder Escape schliesst).";
        popup.Closed += (_, _) => meldung.Text = "Geschlossen.";
        oeffner.Click += (_, _) => popup.IsOpen = !popup.IsOpen;
        schliessen.Click += (_, _) => popup.IsOpen = false;

        // Lage wählen.
        var lagen = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 12 };
        foreach (var (name, lage) in new[]
        {
            ("Unten", PlacementMode.Bottom), ("Oben", PlacementMode.Top), ("Rechts", PlacementMode.Right),
            ("Links", PlacementMode.Left), ("Mittig", PlacementMode.Center),
        })
        {
            var feld = new RadioButton { Content = name, GroupName = "PopupLage", IsChecked = lage == PlacementMode.Bottom };
            feld.Checked += (_, _) => popup.Placement = lage;
            lagen.Children.Add(feld);
        }

        // Bleibt offen: schliesst nur über die Schaltfläche.
        var bleibt = new CheckBox { Content = "StaysOpen (schliesst nicht bei Klick daneben)" };
        bleibt.Click += (_, _) => popup.StaysOpen = bleibt.IsChecked == true;

        var zeile = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 16, Margin = new Thickness(160, 40, 0, 40) };
        zeile.Children.Add(oeffner);
        zeile.Children.Add(popup);

        var seite = new StackPanel { Spacing = 12 };
        seite.Children.Add(lagen);
        seite.Children.Add(bleibt);
        seite.Children.Add(zeile);
        seite.Children.Add(meldung);
        return seite;
    }
}