Zum Inhalt
Kuonen.UI

Window und Dialoge

Ein Fenster mit Titel, Grösse und Zustand. Ein Fenster mit Owner gehört seinem Besitzer (schliesst mit ihm). ZeigeDialogAsync zeigt es modal: der Besitzer ist gesperrt, bis DialogResult gesetzt oder das Fenster geschlossen wird. Closing kann das Schliessen abbrechen.

Vorführung: Window und DialogeVorführung: Window und Dialoge

KXAML

WindowSeite.kxaml
<StackPanel xmlns="https://ui.kuonen.org/kxaml"
            xmlns:x="https://ui.kuonen.org/kxaml/x"
            x:Class="Kuonen.UI.Galerie.Seiten.WindowVorfuehrung"
            Spacing="12">
  <StackPanel Orientation="Horizontal" Spacing="8">
    <!-- Ein gewöhnliches, besessenes Fenster und ein modaler Dialog mit Ergebnis; beide baut das Code-Behind. -->
    <Button x:Name="Neu" Content="Neues Fenster" Click="Neu_Click" />
    <Button x:Name="Dialog" Content="Dialog …" Style="{x:Static Fluent.AkzentButton}" Click="Dialog_Click" />
  </StackPanel>
  <CheckBox x:Name="Nachfragen" Content="Beim Schliessen nachfragen (Closing bricht ab)" />
  <TextBlock x:Name="Meldung" Text="Noch kein Fenster geöffnet." TextWrapping="Wrap" />
</StackPanel>
WindowSeite.kxaml.cs
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Ereignisse;
using Kuonen.UI.Layout;
using Kuonen.UI.Themes;

namespace Kuonen.UI.Galerie.Seiten;

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

/// <summary>KXAML-Fassung der Window-Seite: die Seite steht in WindowSeite.kxaml, die Fenster entstehen hier beim Klick.</summary>
public sealed partial class WindowVorfuehrung
{
    public WindowVorfuehrung() => InitializeComponent();

    // Das Fenster, in dem diese Seite steht: Besitzer der neuen Fenster.
    private static Window? FensterVon(Visual element)
    {
        for (Visual? v = element; v is not null; v = v.VisualParent)
            if (v is Window fenster) return fenster;
        return null;
    }

    // Das Unterfenster folgt dem Theme seines Besitzers, solange es offen ist (Hell/Dunkel der Galerie, Systemwechsel).
    private static void FolgeTheme(Window besitzer, Window fenster)
    {
        fenster.Theme = besitzer.Theme;
        var abo = besitzer.Abonniere(Window.ThemeProperty, () => fenster.Theme = besitzer.Theme);
        fenster.Closed += (_, _) => abo.Dispose();
    }

    private void Neu_Click(object sender, RoutedEventArgs e)
    {
        if (FensterVon(Neu) is not { } besitzer) return;
        var zu = new Button { Content = "Schliessen", HorizontalAlignment = HorizontalAlignment.Left };
        var inhalt = new StackPanel { Spacing = 12, Margin = new Thickness(16) };
        inhalt.Children.Add(new TextBlock { Text = "Ein Fenster der Galerie. Es schliesst mit seinem Besitzer." });
        inhalt.Children.Add(zu);
        var fenster = new Window { Title = "Neues Fenster", Width = 360, Height = 160, Owner = besitzer, Content = inhalt };
        FolgeTheme(besitzer, fenster);
        bool abgebrochen = false;
        fenster.Closing += (_, a) =>
        {
            if (Nachfragen.IsChecked != true || abgebrochen) return;
            a.Cancel = true; // einmal abbrechen; der nächste Versuch schliesst
            abgebrochen = true;
            Meldung.Text = "Schliessen abgebrochen (Closing). Noch einmal versuchen schliesst.";
        };
        fenster.Closed += (_, _) => Meldung.Text = "Fenster geschlossen.";
        zu.Click += (_, _) => fenster.Close();
        fenster.Show();
        Meldung.Text = "Fenster geöffnet.";
    }

    private async void Dialog_Click(object sender, RoutedEventArgs e)
    {
        if (FensterVon(Dialog) is not { } besitzer) return;
        var ja = new Button { Content = "Ja", Style = Fluent.AkzentButton, MinWidth = 80 };
        var nein = new Button { Content = "Nein", MinWidth = 80 };
        var knoepfe = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8, HorizontalAlignment = HorizontalAlignment.Right };
        knoepfe.Children.Add(ja);
        knoepfe.Children.Add(nein);
        var inhalt = new DockPanel { Margin = new Thickness(16) };
        DockPanel.SetDock(knoepfe, Dock.Bottom);
        inhalt.Children.Add(knoepfe);
        inhalt.Children.Add(new TextBlock { Text = "Änderungen übernehmen?", TextWrapping = TextWrapping.Wrap });
        var fenster = new Window { Title = "Frage", Width = 320, Height = 140, Owner = besitzer, Content = inhalt };
        FolgeTheme(besitzer, fenster);
        ja.Click += (_, _) => fenster.DialogResult = true;
        nein.Click += (_, _) => fenster.DialogResult = false;
        Meldung.Text = "Dialog offen; das Hauptfenster ist gesperrt.";
        bool? ergebnis = await fenster.ZeigeDialogAsync();
        Meldung.Text = ergebnis switch { true => "Antwort: Ja.", false => "Antwort: Nein.", null => "Ohne Antwort geschlossen." };
    }
}

C#

WindowSeite.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="Window"/> und modale Dialoge.</summary>
public sealed partial class WindowSeite : GalerieSeite
{
    public override string Titel => "Window und Dialoge";

    public override string Beschreibung =>
        "Ein Fenster mit Titel, Grösse und Zustand. Ein Fenster mit Owner gehört seinem Besitzer (schliesst mit ihm). "
        + "ZeigeDialogAsync zeigt es modal: der Besitzer ist gesperrt, bis DialogResult gesetzt oder das Fenster "
        + "geschlossen wird. Closing kann das Schliessen abbrechen.";

    public override string Stichworte => "Fenster Dialog modal Owner Besitzer DialogResult ZeigeDialogAsync Closing Schliessen abbrechen WindowState";

    public override string Datei => nameof(WindowSeite);

    public override UIElement Baue()
    {
        var meldung = new TextBlock { Text = "Noch kein Fenster geöffnet.", TextWrapping = TextWrapping.Wrap };

        // Das Fenster, in dem diese Seite steht: Besitzer der neuen Fenster.
        static Window? FensterVon(Visual element)
        {
            for (Visual? v = element; v is not null; v = v.VisualParent)
                if (v is Window fenster) return fenster;
            return null;
        }

        // Das Unterfenster folgt dem Theme seines Besitzers, solange es offen ist (Hell/Dunkel der Galerie, Systemwechsel).
        static void FolgeTheme(Window besitzer, Window fenster)
        {
            fenster.Theme = besitzer.Theme;
            var abo = besitzer.Abonniere(Window.ThemeProperty, () => fenster.Theme = besitzer.Theme);
            fenster.Closed += (_, _) => abo.Dispose();
        }

        var nachfragen = new CheckBox { Content = "Beim Schliessen nachfragen (Closing bricht ab)" };

        // Ein gewöhnliches, besessenes Fenster.
        var neu = new Button { Content = "Neues Fenster" };
        neu.Click += (_, _) =>
        {
            if (FensterVon(neu) is not { } besitzer) return;
            var zu = new Button { Content = "Schliessen", HorizontalAlignment = HorizontalAlignment.Left };
            var inhalt = new StackPanel { Spacing = 12, Margin = new Thickness(16) };
            inhalt.Children.Add(new TextBlock { Text = "Ein Fenster der Galerie. Es schliesst mit seinem Besitzer." });
            inhalt.Children.Add(zu);
            var fenster = new Window { Title = "Neues Fenster", Width = 360, Height = 160, Owner = besitzer, Content = inhalt };
            FolgeTheme(besitzer, fenster);
            bool abgebrochen = false;
            fenster.Closing += (_, e) =>
            {
                if (nachfragen.IsChecked != true || abgebrochen) return;
                e.Cancel = true; // einmal abbrechen; der nächste Versuch schliesst
                abgebrochen = true;
                meldung.Text = "Schliessen abgebrochen (Closing). Noch einmal versuchen schliesst.";
            };
            fenster.Closed += (_, _) => meldung.Text = "Fenster geschlossen.";
            zu.Click += (_, _) => fenster.Close();
            fenster.Show();
            meldung.Text = "Fenster geöffnet.";
        };

        // Ein modaler Dialog mit Ergebnis.
        var dialog = new Button { Content = "Dialog …", Style = Fluent.AkzentButton };
        dialog.Click += async (_, _) =>
        {
            if (FensterVon(dialog) is not { } besitzer) return;
            var ja = new Button { Content = "Ja", Style = Fluent.AkzentButton, MinWidth = 80 };
            var nein = new Button { Content = "Nein", MinWidth = 80 };
            var knoepfe = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8, HorizontalAlignment = HorizontalAlignment.Right };
            knoepfe.Children.Add(ja);
            knoepfe.Children.Add(nein);
            var inhalt = new DockPanel { Margin = new Thickness(16) };
            DockPanel.SetDock(knoepfe, Dock.Bottom);
            inhalt.Children.Add(knoepfe);
            inhalt.Children.Add(new TextBlock { Text = "Änderungen übernehmen?", TextWrapping = TextWrapping.Wrap });
            var fenster = new Window { Title = "Frage", Width = 320, Height = 140, Owner = besitzer, Content = inhalt };
            FolgeTheme(besitzer, fenster);
            ja.Click += (_, _) => fenster.DialogResult = true;
            nein.Click += (_, _) => fenster.DialogResult = false;
            meldung.Text = "Dialog offen; das Hauptfenster ist gesperrt.";
            bool? ergebnis = await fenster.ZeigeDialogAsync();
            meldung.Text = ergebnis switch { true => "Antwort: Ja.", false => "Antwort: Nein.", null => "Ohne Antwort geschlossen." };
        };

        var reihe = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8 };
        reihe.Children.Add(neu);
        reihe.Children.Add(dialog);

        var seite = new StackPanel { Spacing = 12 };
        seite.Children.Add(reihe);
        seite.Children.Add(nachfragen);
        seite.Children.Add(meldung);
        return seite;
    }
}