DeskCore 1.0.0
Desktop-Icons in eigene Kategorien sortieren: Windows-11-Design (hell/dunkel), Desktop-Boxen, automatisches Einsortieren nach Regeln, Rückgängig, Suche, Infobereich mit Tastenkürzel, Sicherung als ZIP und Installer ohne Adminrechte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace DeskCore;
|
||||
|
||||
/// <summary>Dialoge im Stil eines Windows-11-ContentDialogs.</summary>
|
||||
public static class Dialog
|
||||
{
|
||||
public static bool Confirm(Window owner, string title, string message, string primary = "OK", string? secondary = "Abbrechen") =>
|
||||
Show(owner, title, Text(message), primary, secondary, null);
|
||||
|
||||
public static void Info(Window owner, string title, string message) =>
|
||||
Show(owner, title, Text(message), "OK", null, null);
|
||||
|
||||
/// <summary>Eingabedialog. validate gibt eine Fehlermeldung oder null zurück.</summary>
|
||||
public static string? Prompt(Window owner, string title, string label, string initial, string primary, Func<string, string?> validate)
|
||||
{
|
||||
var box = new TextBox { Text = initial, Margin = new Thickness(0, 8, 0, 0) };
|
||||
var panel = new StackPanel();
|
||||
panel.Children.Add(Text(label, secondary: true));
|
||||
panel.Children.Add(box);
|
||||
var ok = Show(owner, title, panel, primary, "Abbrechen", () => validate(box.Text), box);
|
||||
return ok ? box.Text.Trim() : null;
|
||||
}
|
||||
|
||||
public static TextBlock Text(string text, bool secondary = false) => new()
|
||||
{
|
||||
Text = text, TextWrapping = TextWrapping.Wrap, LineHeight = 20,
|
||||
Foreground = (Brush)Application.Current.Resources[secondary ? "TextSecondaryBrush" : "TextBrush"],
|
||||
};
|
||||
|
||||
/// <summary>Allgemeiner Dialog mit beliebigem Inhalt. validate: Fehlermeldung oder null.</summary>
|
||||
public static bool Show(Window owner, string title, UIElement content, string primary, string? secondary,
|
||||
Func<string?>? validate, IInputElement? focus = null, double width = 448)
|
||||
{
|
||||
var res = Application.Current.Resources;
|
||||
|
||||
var error = new TextBlock
|
||||
{
|
||||
Foreground = (Brush)res["DangerBrush"], FontSize = 12, Margin = new Thickness(0, 8, 0, 0),
|
||||
TextWrapping = TextWrapping.Wrap, Visibility = Visibility.Collapsed,
|
||||
};
|
||||
|
||||
var body = new StackPanel { Margin = new Thickness(24, 22, 24, 24) };
|
||||
body.Children.Add(new TextBlock
|
||||
{
|
||||
Text = title, FontSize = 20, FontWeight = FontWeights.SemiBold, Margin = new Thickness(0, 0, 0, 12),
|
||||
FontFamily = (FontFamily)res["DisplayFont"], TextWrapping = TextWrapping.Wrap,
|
||||
});
|
||||
body.Children.Add(content);
|
||||
body.Children.Add(error);
|
||||
|
||||
var ok = new Button { Content = primary, IsDefault = true, Style = (Style)res["AccentButton"] };
|
||||
var footer = new Grid { Margin = new Thickness(24) };
|
||||
footer.ColumnDefinitions.Add(new ColumnDefinition());
|
||||
footer.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(8) });
|
||||
footer.ColumnDefinitions.Add(new ColumnDefinition());
|
||||
if (secondary is not null)
|
||||
{
|
||||
var cancel = new Button { Content = secondary, IsCancel = true };
|
||||
Grid.SetColumn(cancel, 2);
|
||||
footer.Children.Add(cancel);
|
||||
}
|
||||
else Grid.SetColumn(ok, 2); // einzelner Button rechts, wie bei Windows 11
|
||||
footer.Children.Add(ok);
|
||||
|
||||
var layout = new DockPanel();
|
||||
var footerBorder = new Border
|
||||
{
|
||||
Background = (Brush)res["DialogFooterBrush"], Child = footer,
|
||||
BorderBrush = (Brush)res["FlyoutStrokeBrush"], BorderThickness = new Thickness(0, 1, 0, 0),
|
||||
CornerRadius = new CornerRadius(0, 0, 8, 8),
|
||||
};
|
||||
DockPanel.SetDock(footerBorder, Dock.Bottom);
|
||||
layout.Children.Add(footerBorder);
|
||||
layout.Children.Add(new ScrollViewer { Content = body, VerticalScrollBarVisibility = ScrollBarVisibility.Auto, MaxHeight = 560 });
|
||||
|
||||
var dlg = new Window
|
||||
{
|
||||
Owner = owner.IsVisible ? owner : null, Title = title, Width = width + 64, SizeToContent = SizeToContent.Height,
|
||||
WindowStyle = WindowStyle.None, AllowsTransparency = true, Background = Brushes.Transparent,
|
||||
ResizeMode = ResizeMode.NoResize, ShowInTaskbar = !owner.IsVisible, Topmost = !owner.IsVisible,
|
||||
WindowStartupLocation = owner.IsVisible ? WindowStartupLocation.CenterOwner : WindowStartupLocation.CenterScreen,
|
||||
FontFamily = (FontFamily)res["UiFont"], FontSize = 14,
|
||||
Foreground = (Brush)res["TextBrush"],
|
||||
Content = new Border
|
||||
{
|
||||
Margin = new Thickness(32), CornerRadius = new CornerRadius(8),
|
||||
Background = (Brush)res["LayerBrush"],
|
||||
BorderBrush = (Brush)res["FlyoutStrokeBrush"], BorderThickness = new Thickness(1),
|
||||
Effect = (System.Windows.Media.Effects.Effect)res["DialogShadow"], Child = layout,
|
||||
},
|
||||
};
|
||||
|
||||
ok.Click += (_, _) =>
|
||||
{
|
||||
if (validate?.Invoke() is { } err)
|
||||
{
|
||||
error.Text = err;
|
||||
error.Visibility = Visibility.Visible;
|
||||
(focus as UIElement)?.Focus();
|
||||
return;
|
||||
}
|
||||
dlg.DialogResult = true;
|
||||
};
|
||||
if (focus is TextBox tb) tb.TextChanged += (_, _) => error.Visibility = Visibility.Collapsed;
|
||||
|
||||
dlg.PreviewKeyDown += (_, e) => { if (e.Key == Key.Escape) dlg.Close(); };
|
||||
dlg.MouseLeftButtonDown += (_, e) => { if (e.ButtonState == MouseButtonState.Pressed) dlg.DragMove(); };
|
||||
dlg.Loaded += (_, _) =>
|
||||
{
|
||||
if (focus is TextBox t) { t.Focus(); t.SelectAll(); }
|
||||
else if (focus is UIElement u) u.Focus();
|
||||
else ok.Focus();
|
||||
};
|
||||
|
||||
(owner as MainWindow)?.SetDimmed(true);
|
||||
try
|
||||
{
|
||||
return dlg.ShowDialog() == true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
(owner as MainWindow)?.SetDimmed(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user