TaskDialog
Ein Aufgabendialog wie der TaskDialog von WinForms, nur asynchron: ZeigeAsync öffnet ein modales Fenster mit dem Inhalt einer TaskDialogPage und liefert den Knopf, der es geschlossen hat. Befehlslinks, Optionen, „Nicht mehr fragen“, einklappbare Details, Fortschritt, Fusszeile und Links im Text; Navigate wechselt die Seite im offenen Fenster. Der Dialog öffnet nie selbst eine Adresse: ein Link meldet nur LinkClicked.


KXAML
TaskDialogSeite.kxaml
<StackPanel xmlns="https://ui.kuonen.org/kxaml"
xmlns:x="https://ui.kuonen.org/kxaml/x"
x:Class="Kuonen.UI.Galerie.Seiten.TaskDialogVorfuehrung"
Spacing="12">
<TextBlock Text="Beispiele" FontWeight="SemiBold" />
<Button x:Name="Datei" Content="Datei ersetzen?" Style="{x:Static Fluent.AkzentButton}" Click="Datei_Click" />
<Button x:Name="Fortschritt" Content="Fortschritt und Navigation" Click="Fortschritt_Click" />
<Button x:Name="Links" Content="Links im Text" Click="Links_Click" />
<TextBlock x:Name="Ergebnis" Text="Noch kein Dialog gezeigt." TextWrapping="Wrap" />
</StackPanel>TaskDialogSeite.kxaml.cs
using Kuonen.UI;
using Kuonen.UI.Controls;
using Kuonen.UI.Ereignisse;
namespace Kuonen.UI.Galerie.Seiten;
public sealed partial class TaskDialogSeite
{
protected override Func<UIElement>? KxamlFabrik => () => new TaskDialogVorfuehrung();
}
/// <summary>KXAML-Fassung der TaskDialog-Seite: die Knöpfe stehen in TaskDialogSeite.kxaml, die Seiten des Dialogs (keine Elemente) baut der Code-Behind.</summary>
public sealed partial class TaskDialogVorfuehrung
{
public TaskDialogVorfuehrung() => InitializeComponent();
private async void Datei_Click(object sender, RoutedEventArgs e)
{
if (TaskDialogSeite.FensterVon(Datei) is not { } besitzer) return;
var seite = TaskDialogSeite.DateiSeite();
Ergebnis.Text = "Der Dialog ist offen; das Fenster ist gesperrt.";
var wahl = await TaskDialog.ZeigeAsync(besitzer, seite);
Ergebnis.Text = TaskDialogSeite.BeschreibeDatei(wahl, seite);
}
private async void Fortschritt_Click(object sender, RoutedEventArgs e)
{
if (TaskDialogSeite.FensterVon(Fortschritt) is not { } besitzer) return;
Ergebnis.Text = "Der Dialog ist offen; das Fenster ist gesperrt.";
var wahl = await TaskDialog.ZeigeAsync(besitzer, TaskDialogSeite.FortschrittSeite());
Ergebnis.Text = "Ergebnis: " + wahl.Text + ".";
}
private async void Links_Click(object sender, RoutedEventArgs e)
{
if (TaskDialogSeite.FensterVon(Links) is not { } besitzer) return;
Ergebnis.Text = "Der Dialog ist offen; ein Link meldet nur seine Adresse.";
await TaskDialog.ZeigeAsync(besitzer, TaskDialogSeite.LinkSeite(href => Ergebnis.Text = "Link angeklickt: " + href));
}
}C#
TaskDialogSeite.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="TaskDialog"/> mit Seiten, Befehlslinks, Optionen, Kontrollkästchen, Details, Fortschritt, Fusszeile und Links.</summary>
public sealed partial class TaskDialogSeite : GalerieSeite
{
public override string Titel => "TaskDialog";
public override string Beschreibung =>
"Ein Aufgabendialog wie der TaskDialog von WinForms, nur asynchron: ZeigeAsync öffnet ein modales Fenster mit dem Inhalt einer TaskDialogPage und liefert den "
+ "Knopf, der es geschlossen hat. Befehlslinks, Optionen, „Nicht mehr fragen“, einklappbare Details, Fortschritt, Fusszeile und Links im Text; Navigate wechselt die "
+ "Seite im offenen Fenster. Der Dialog öffnet nie selbst eine Adresse: ein Link meldet nur LinkClicked.";
public override string Stichworte => "TaskDialog Aufgabendialog TaskDialogPage Befehlslink CommandLink Navigate Fortschritt Details Expander Fusszeile Footnote Kontrollkästchen Verification Optionen RadioButtons EnableLinks LinkClicked ZeigeAsync";
public override string Datei => nameof(TaskDialogSeite);
/// <summary>„Datei ersetzen?“: Befehlslinks, „Nicht mehr fragen“, Details und ein Abbrechen-Knopf.</summary>
internal static TaskDialogPage DateiSeite()
{
var seite = new TaskDialogPage
{
Caption = "Datei kopieren",
Heading = "Das Ziel enthält schon eine Datei „Bericht.pdf“.",
Text = "Was soll mit der vorhandenen Datei geschehen?",
Icon = TaskDialogIcon.Warning,
Verification = new TaskDialogVerificationCheckBox("Für alle weiteren Dateien übernehmen"),
Expander = new TaskDialogExpander("Vorhanden: 12.04.2026, 1,2 MB\nNeu: 11.10.2026, 1,4 MB"),
};
seite.Buttons.Add(new TaskDialogCommandLinkButton("Ersetzen", "Die vorhandene Datei wird überschrieben."));
seite.Buttons.Add(new TaskDialogCommandLinkButton("Beide behalten", "Die neue Datei bekommt einen anderen Namen."));
seite.Buttons.Add(new TaskDialogCommandLinkButton("Überspringen", "Die vorhandene Datei bleibt, die neue wird nicht kopiert."));
seite.Buttons.Add(TaskDialogButton.Cancel);
return seite;
}
/// <summary>Beschreibt das Ergebnis von <see cref="DateiSeite"/> in einer Zeile.</summary>
internal static string BeschreibeDatei(TaskDialogButton knopf, TaskDialogPage seite) =>
$"Ergebnis: {knopf.Text}; „Für alle weiteren Dateien übernehmen“: {(seite.Verification!.Checked ? "ja" : "nein")}.";
/// <summary>
/// Eine Seite mit Fortschritt: jeder Druck auf „Weiter“ rückt den Balken vor (kein Timer), bei 100 % wechselt <see cref="TaskDialogPage.Navigate"/> auf die
/// Seite „Fertig“.
/// </summary>
internal static TaskDialogPage FortschrittSeite()
{
var fortschritt = new TaskDialogProgressBar { Maximum = 100 };
var weiter = new TaskDialogButton("Weiter") { AllowCloseDialog = false };
var seite = new TaskDialogPage
{
Caption = "Kopieren",
Heading = "Die Dateien werden kopiert …",
Text = "Jeder Druck auf „Weiter“ rückt den Balken um 20 vor.",
Icon = TaskDialogIcon.Information,
ProgressBar = fortschritt,
};
seite.Buttons.Add(weiter);
seite.Buttons.Add(TaskDialogButton.Cancel);
weiter.Click += (_, _) =>
{
fortschritt.Value = Math.Min(100, fortschritt.Value + 20);
seite.Text = $"{fortschritt.Value} % kopiert.";
if (fortschritt.Value < 100) return;
var fertig = new TaskDialogPage
{
Caption = "Kopieren",
Heading = "Fertig",
Text = "Alle Dateien sind kopiert.",
Icon = TaskDialogIcon.ShieldSuccessGreenBar,
};
fertig.Buttons.Add(TaskDialogButton.Close);
seite.Navigate(fertig);
};
return seite;
}
/// <summary>Eine Seite mit Links im Text und in der Fusszeile; <paramref name="gewaehlt"/> bekommt den <c>href</c> des angeklickten Links.</summary>
internal static TaskDialogPage LinkSeite(Action<string> gewaehlt)
{
var seite = new TaskDialogPage
{
Caption = "Links",
Heading = "Hilfe zum Kopieren",
Text = "Lesen Sie <a href=\"https://beispiel.ch/hilfe/kopieren\">die Hilfe</a> oder <a href=\"thema:ersetzen\">das Thema „Ersetzen“</a>.",
Icon = TaskDialogIcon.Information,
EnableLinks = true,
Footnote = new TaskDialogFootnote("Mehr unter <a href=\"https://beispiel.ch\">beispiel.ch</a>."),
};
seite.Buttons.Add(TaskDialogButton.Close);
seite.LinkClicked += (_, e) => gewaehlt(e.LinkHref);
return seite;
}
// Das Fenster, in dem diese Seite steht: Besitzer des Dialogs.
internal 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;
}
public override UIElement Baue()
{
var ergebnis = new TextBlock { Text = "Noch kein Dialog gezeigt.", TextWrapping = TextWrapping.Wrap };
var datei = new Button { Content = "Datei ersetzen?", Style = Fluent.AkzentButton };
datei.Click += async (_, _) =>
{
if (FensterVon(datei) is not { } besitzer) return;
var seite = DateiSeite();
ergebnis.Text = "Der Dialog ist offen; das Fenster ist gesperrt.";
var wahl = await TaskDialog.ZeigeAsync(besitzer, seite);
ergebnis.Text = BeschreibeDatei(wahl, seite);
};
var fortschritt = new Button { Content = "Fortschritt und Navigation" };
fortschritt.Click += async (_, _) =>
{
if (FensterVon(fortschritt) is not { } besitzer) return;
ergebnis.Text = "Der Dialog ist offen; das Fenster ist gesperrt.";
var wahl = await TaskDialog.ZeigeAsync(besitzer, FortschrittSeite());
ergebnis.Text = "Ergebnis: " + wahl.Text + ".";
};
var links = new Button { Content = "Links im Text" };
links.Click += async (_, _) =>
{
if (FensterVon(links) is not { } besitzer) return;
ergebnis.Text = "Der Dialog ist offen; ein Link meldet nur seine Adresse.";
await TaskDialog.ZeigeAsync(besitzer, LinkSeite(href => ergebnis.Text = "Link angeklickt: " + href));
};
var seiteWurzel = new StackPanel { Spacing = 12 };
seiteWurzel.Children.Add(new TextBlock { Text = "Beispiele", FontWeight = 600 });
seiteWurzel.Children.Add(datei);
seiteWurzel.Children.Add(fortschritt);
seiteWurzel.Children.Add(links);
seiteWurzel.Children.Add(ergebnis);
return seiteWurzel;
}
}