{"id":216,"date":"2026-05-09T11:42:10","date_gmt":"2026-05-09T11:42:10","guid":{"rendered":"https:\/\/www.fabricioruch.ch\/?p=216"},"modified":"2026-05-09T11:42:10","modified_gmt":"2026-05-09T11:42:10","slug":"decoupling-in-wpf-using-messagebox-as-example","status":"publish","type":"post","link":"https:\/\/www.fabricioruch.ch\/?p=216","title":{"rendered":"Decoupling in WPF Using MessageBox as Example"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">A Deep-Dive with Real Chrona Code Examples<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.fabricioruch.ch\/wp-content\/uploads\/2026\/05\/image-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"586\" src=\"https:\/\/www.fabricioruch.ch\/wp-content\/uploads\/2026\/05\/image-2-1024x586.png\" alt=\"\" class=\"wp-image-217\" srcset=\"https:\/\/www.fabricioruch.ch\/wp-content\/uploads\/2026\/05\/image-2-1024x586.png 1024w, https:\/\/www.fabricioruch.ch\/wp-content\/uploads\/2026\/05\/image-2-300x172.png 300w, https:\/\/www.fabricioruch.ch\/wp-content\/uploads\/2026\/05\/image-2-768x439.png 768w, https:\/\/www.fabricioruch.ch\/wp-content\/uploads\/2026\/05\/image-2.png 1386w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Many WPF applications begin with direct <code>MessageBox.Show(...)<\/code> calls.<\/p>\n\n\n\n<p>At first, this feels completely reasonable. A save confirmation here, an error dialog there, a warning before deletion. The implementation is fast, obvious, and immediately functional.<\/p>\n\n\n\n<p>As the application grows, however, this becomes an architectural problem.<\/p>\n\n\n\n<p>Once <code>MessageBox.Show(...)<\/code> is scattered across ViewModels, services, and workflow logic, UI behavior becomes tightly coupled to application behavior. Every feature decides independently how dialogs should work. Every ViewModel depends directly on WPF dialog primitives. Every future redesign requires widespread refactoring.<\/p>\n\n\n\n<p>Chrona takes a different approach.<\/p>\n\n\n\n<p>Instead of coupling feature code directly to WPF dialogs, the application routes all dialog interaction through a layered abstraction:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Feature Code\n    \u2193\nIDialogService\n    \u2193\nIMessageDialogHost\n    \u2193\nCustomDialogHost\n    \u2193\nCustomMessageDialogWindow\n<\/code><\/pre>\n\n\n\n<p>This separation is architecturally strong because the business and workflow layers no longer depend on concrete UI rendering details.<\/p>\n\n\n\n<p>The result is a dialog system that is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>replaceable<\/li>\n\n\n\n<li>testable<\/li>\n\n\n\n<li>design-consistent<\/li>\n\n\n\n<li>future-proof<\/li>\n\n\n\n<li>independent from direct WPF primitives<\/li>\n<\/ul>\n\n\n\n<p>That matters far more in production systems than most MVVM tutorials acknowledge.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">The Real Problem with MessageBox.Show<\/h1>\n\n\n\n<p>A direct message box call looks harmless:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MessageBox.Show(\n    \"Entry saved successfully.\",\n    \"Information\",\n    MessageBoxButton.OK,\n    MessageBoxImage.Information);\n<\/code><\/pre>\n\n\n\n<p>The problem is not the individual call.<\/p>\n\n\n\n<p>The problem is architectural spread.<\/p>\n\n\n\n<p>Once dozens or hundreds of these calls exist across a desktop application, several issues emerge:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ViewModels become tied to WPF types.\nDialog design becomes inconsistent.\nTesting becomes harder.\nModal behavior becomes fragmented.\nFuture redesigns require mass refactoring.<\/code><\/pre>\n\n\n\n<p>Even worse, the application logic starts speaking in framework-specific terminology.<\/p>\n\n\n\n<p>A ViewModel should not need to know what <code>MessageBoxButton.YesNoCancel<\/code> means. The ViewModel should only express intent:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>I need a confirmation.\nI need to show an error.\nI need to notify the user.<\/code><\/pre>\n\n\n\n<p>How that intent is rendered visually should be infrastructure behavior.<\/p>\n\n\n\n<p>Chrona separates exactly these concerns.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Replacing WPF Types with Application Semantics<\/h1>\n\n\n\n<p>The first important architectural step in Chrona is removing WPF dialog types from the application-facing API.<\/p>\n\n\n\n<p>Instead of exposing <code>MessageBoxButton<\/code>, <code>MessageBoxImage<\/code>, or <code>MessageBoxResult<\/code>, the application defines its own dialog semantics.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>namespace Chrona.Services.App.Interfaces;\n\npublic enum DialogButtons\n{\n    Ok,\n    OkCancel,\n    YesNo,\n    YesNoCancel\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>namespace Chrona.Services.App.Interfaces;\n\npublic enum DialogIcon\n{\n    None,\n    Information,\n    Warning,\n    Error,\n    Question\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>namespace Chrona.Services.App.Interfaces;\n\npublic enum DialogResult\n{\n    None,\n    Ok,\n    Cancel,\n    Yes,\n    No\n}<\/code><\/pre>\n\n\n\n<p>This is an extremely important architectural move.<\/p>\n\n\n\n<p>The ViewModel and service layers now speak in application language instead of WPF language.<\/p>\n\n\n\n<p>That creates major long-term flexibility.<\/p>\n\n\n\n<p>The application no longer depends on:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MessageBoxButton\nMessageBoxImage\nMessageBoxResult<\/code><\/pre>\n\n\n\n<p>which means the UI framework can evolve independently from the application workflows.<\/p>\n\n\n\n<p>This may sound subtle, but it is one of the strongest decoupling decisions in the entire dialog architecture.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">High-Level Feature API Through IDialogService<\/h1>\n\n\n\n<p>The feature-facing API remains intentionally high-level and workflow-oriented.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>namespace Chrona.Services.App.Interfaces;\n\npublic interface IDialogService\n{\n    DialogResult ShowDialog(\n        string message,\n        string title,\n        DialogButtons buttons = DialogButtons.Ok,\n        DialogIcon icon = DialogIcon.Information);\n\n    Task&lt;DialogResult&gt; ShowDialogAsync(\n        string message,\n        string title,\n        DialogButtons buttons = DialogButtons.Ok,\n        DialogIcon icon = DialogIcon.Information);\n\n    bool Confirm(\n        string message,\n        string title,\n        DialogIcon icon = DialogIcon.Question);\n\n    string? ShowOpenFileDialog(\n        string filter,\n        string title);\n\n    string? ShowSaveFileDialog(\n        string filter,\n        string defaultFileName);\n\n    \/\/ Toast notifications\n    void ShowToast(string message, DialogIcon icon);\n\n    void ShowSuccess(\n        string message,\n        IReadOnlyList&lt;ToastActionOption&gt;? actions = null);\n}\n<\/code><\/pre>\n\n\n\n<p>This is good service design because the call sites remain readable and intention-driven.<\/p>\n\n\n\n<p>Feature code does not need to know:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>whether the dialog is modal<\/li>\n\n\n\n<li>whether a custom overlay is used<\/li>\n\n\n\n<li>whether a native WPF window is used<\/li>\n\n\n\n<li>whether notifications appear as toasts<\/li>\n\n\n\n<li>whether dialogs are queued internally<\/li>\n<\/ul>\n\n\n\n<p>The ViewModel simply expresses intent.<\/p>\n\n\n\n<p>That keeps workflow logic clean.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">IMessageDialogHost: The Critical Architectural Boundary<\/h1>\n\n\n\n<p>The actual decoupling point is <code>IMessageDialogHost<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>namespace Chrona.Services.App.Interfaces;\n\npublic interface IMessageDialogHost\n{\n    DialogResult ShowDialog(\n        string message,\n        string title,\n        DialogButtons buttons,\n        DialogIcon icon);\n}\n<\/code><\/pre>\n\n\n\n<p>This interface is the true boundary between:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>application interaction policy<\/code><\/pre>\n\n\n\n<p>and:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>concrete UI rendering<\/code><\/pre>\n\n\n\n<p>Everything above this interface remains stable.<\/p>\n\n\n\n<p>Everything below it becomes replaceable.<\/p>\n\n\n\n<p>That separation gives the architecture significant flexibility.<\/p>\n\n\n\n<p>The application can later replace:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>native WPF windows<\/li>\n\n\n\n<li>MahApps dialogs<\/li>\n\n\n\n<li>Fluent overlays<\/li>\n\n\n\n<li>custom modal systems<\/li>\n\n\n\n<li>accessibility-enhanced dialogs<\/li>\n\n\n\n<li>web-style popup layers<\/li>\n<\/ul>\n\n\n\n<p>without rewriting feature logic.<\/p>\n\n\n\n<p>That is exactly what good desktop architecture should enable.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">DialogService as a Policy Layer<\/h1>\n\n\n\n<p>Chrona\u2019s <code>DialogService<\/code> does not render dialogs directly.<\/p>\n\n\n\n<p>Instead, it acts as an interaction-policy layer.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class DialogService : IDialogService\n{\n    private readonly IMessageDialogHost _messageDialogHost;\n    private readonly IToastService _toastService;\n\n    public DialogService(\n        IToastService toastService,\n        IMessageDialogHost messageDialogHost)\n    {\n        _toastService = toastService;\n        _messageDialogHost = messageDialogHost;\n    }\n\n    public DialogResult ShowDialog(\n        string message,\n        string title,\n        DialogButtons buttons = DialogButtons.Ok,\n        DialogIcon icon = DialogIcon.Information)\n    {\n        \/\/ Yes\/No questions remain modal\n        if (buttons == DialogButtons.YesNo ||\n            buttons == DialogButtons.YesNoCancel)\n        {\n            return _messageDialogHost.ShowDialog(\n                message,\n                title,\n                buttons,\n                icon);\n        }\n\n        \/\/ Simple informational messages use toasts\n        ShowToast(message, icon);\n\n        return DialogResult.Ok;\n    }\n}<\/code><\/pre>\n\n\n\n<p>This is a very strong pattern.<\/p>\n\n\n\n<p>The service owns interaction policy:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>When should interaction be modal?\nWhen should interaction be non-blocking?<\/code><\/pre>\n\n\n\n<p>But it does not own rendering.<\/p>\n\n\n\n<p>Rendering belongs to the dialog host.<\/p>\n\n\n\n<p>That separation keeps responsibilities extremely clean.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Modal vs Non-Modal UX Policy<\/h1>\n\n\n\n<p>Chrona distinguishes between two fundamentally different interaction categories.<\/p>\n\n\n\n<p>Decision workflows remain modal:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Yes\/No\nYes\/No\/Cancel<\/code><\/pre>\n\n\n\n<p>because the user must explicitly decide something before continuing.<\/p>\n\n\n\n<p>Informational messages become non-blocking toast notifications:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Save successful\nExport completed\nOperation finished<\/code><\/pre>\n\n\n\n<p>This dramatically improves UX quality.<\/p>\n\n\n\n<p>Users are interrupted only when interruption is actually necessary.<\/p>\n\n\n\n<p>Many desktop applications overuse modal dialogs and unintentionally create interaction fatigue.<\/p>\n\n\n\n<p>Chrona avoids that by centralizing interaction policy.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">CustomDialogHost: UI Rendering Infrastructure<\/h1>\n\n\n\n<p>The actual UI rendering happens inside <code>CustomDialogHost<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class CustomDialogHost : IMessageDialogHost\n{\n    public DialogResult ShowDialog(\n        string message,\n        string title,\n        DialogButtons buttons,\n        DialogIcon icon)\n    {\n        if (Application.Current?.Dispatcher is not null &amp;&amp;\n            !Application.Current.Dispatcher.CheckAccess())\n        {\n            return Application.Current.Dispatcher.Invoke(\n                () =&gt; ShowDialogCore(\n                    message,\n                    title,\n                    buttons,\n                    icon));\n        }\n\n        return ShowDialogCore(\n            message,\n            title,\n            buttons,\n            icon);\n    }\n\n    private static DialogResult ShowDialogCore(\n        string message,\n        string title,\n        DialogButtons buttons,\n        DialogIcon icon)\n    {\n        var dialog =\n            new CustomMessageDialogWindow(\n                title,\n                message,\n                buttons,\n                icon);\n\n        if (Application.Current?.MainWindow is\n            { IsLoaded: true } mainWindow &amp;&amp;\n            mainWindow.IsVisible)\n        {\n            dialog.Owner = mainWindow;\n        }\n\n        dialog.ShowDialog();\n\n        return dialog.DialogOutcome;\n    }\n}\n<\/code><\/pre>\n\n\n\n<p>Several strong implementation details are visible here.<\/p>\n\n\n\n<p>The host handles UI-thread marshaling automatically.<\/p>\n\n\n\n<p>The host assigns dialog ownership to the main window.<\/p>\n\n\n\n<p>The host returns application-level <code>DialogResult<\/code> values rather than WPF-native types.<\/p>\n\n\n\n<p>The host isolates all rendering-specific behavior from application workflows.<\/p>\n\n\n\n<p>This is infrastructure code in the best sense: centralized, replaceable, and invisible to feature logic.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Building a Dialog That Feels Native to the App<\/h1>\n\n\n\n<p>Chrona\u2019s custom dialog window is fully integrated into the application design system.<\/p>\n\n\n\n<p>The dialog uses existing dynamic resources:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SurfaceBrush\nDividerBrush\nPrimaryBrush\nPrimaryLightBrush<\/code><\/pre>\n\n\n\n<p>which makes the dialog visually consistent with the rest of the application.<\/p>\n\n\n\n<p>The shell itself is highly customized:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;Window\n    WindowStartupLocation=\"CenterOwner\"\n    ResizeMode=\"NoResize\"\n    WindowStyle=\"None\"\n    ShowInTaskbar=\"False\"\n    Background=\"Transparent\"\n    AllowsTransparency=\"True\"\n    SizeToContent=\"WidthAndHeight\"\n    MinWidth=\"460\"\n    MaxWidth=\"680\"><\/code><\/pre>\n\n\n\n<p>This is important because native <code>MessageBox<\/code> windows often break visual consistency in modern WPF applications.<\/p>\n\n\n\n<p>Custom dialogs allow:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>branded UX<\/li>\n\n\n\n<li>theme consistency<\/li>\n\n\n\n<li>dark mode support<\/li>\n\n\n\n<li>consistent typography<\/li>\n\n\n\n<li>accessibility improvements<\/li>\n\n\n\n<li>animation support<\/li>\n\n\n\n<li>richer layouts<\/li>\n<\/ul>\n\n\n\n<p>without changing feature logic.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Visual Structure and Theming<\/h1>\n\n\n\n<p>The dialog uses application-level brushes and effects:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;Border\n    Background=\"{DynamicResource SurfaceBrush}\"\n    BorderBrush=\"{DynamicResource DividerBrush}\"\n    BorderThickness=\"1\"\n    CornerRadius=\"12\"><\/code><\/pre>\n\n\n\n<p>along with a shadow effect:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;DropShadowEffect\n    BlurRadius=\"24\"\n    ShadowDepth=\"4\"\n    Opacity=\"0.22\"\n    Color=\"Black\" \/><\/code><\/pre>\n\n\n\n<p>The header includes an icon badge and title region:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;Border\n    Background=\"{DynamicResource BackgroundBrush}\"\n    BorderBrush=\"{DynamicResource DividerBrush}\"\n    BorderThickness=\"0,0,0,1\"><\/code><\/pre>\n\n\n\n<p>while the footer uses application button styles:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;Button\n    Style=\"{DynamicResource SecondaryButtonStyle}\" \/&gt;\n\n&lt;Button\n    Style=\"{DynamicResource PrimaryButtonStyle}\" \/&gt;\n<\/code><\/pre>\n\n\n\n<p>This creates a dialog experience that feels like a natural extension of the application rather than an external operating-system popup.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Mapping Application Semantics to UX<\/h1>\n\n\n\n<p>The code-behind translates dialog semantics into actual visuals.<\/p>\n\n\n\n<p>Icon configuration is centralized:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private void ConfigureIcon(DialogIcon icon)\n{\n    var (kind, badgeKey, iconKey) = icon switch\n    {\n        DialogIcon.Error =&gt;\n            (PackIconMaterialKind.AlertCircle,\n             \"ErrorBrush\",\n             \"OnPrimaryTextBrush\"),\n\n        DialogIcon.Warning =&gt;\n            (PackIconMaterialKind.AlertOutline,\n             \"WarningBrush\",\n             \"OnPrimaryTextBrush\"),\n\n        DialogIcon.Question =&gt;\n            (PackIconMaterialKind.HelpCircleOutline,\n             \"PrimaryLightBrush\",\n             \"PrimaryBrush\"),\n\n        DialogIcon.Information =&gt;\n            (PackIconMaterialKind.InformationOutline,\n             \"PrimaryLightBrush\",\n             \"PrimaryBrush\"),\n\n        _ =&gt;\n            (PackIconMaterialKind.InformationOutline,\n             \"PrimaryLightBrush\",\n             \"PrimaryBrush\")\n    };\n\n    IconGlyph.Kind = kind;\n\n    IconBadge.Background =\n        ResolveBrush(badgeKey, Brushes.LightGray);\n\n    IconGlyph.Foreground =\n        ResolveBrush(iconKey, Brushes.DodgerBlue);\n}\n<\/code><\/pre>\n\n\n\n<p>The dialog window does not expose raw icon implementation details to the application layer. It simply maps semantic intent:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Error\nWarning\nInformation\nQuestion<\/code><\/pre>\n\n\n\n<p>into actual UI styling.<\/p>\n\n\n\n<p>That keeps the application semantics stable while allowing the visual implementation to evolve independently.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Button Configuration and Localization<\/h1>\n\n\n\n<p>Button configuration follows the same pattern.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private void ConfigureButtons(DialogButtons buttons)\n{\n    SecondaryButton.Visibility = Visibility.Collapsed;\n    TertiaryButton.Visibility = Visibility.Collapsed;\n\n    switch (buttons)\n    {\n        case DialogButtons.Ok:\n            PrimaryButton.Content = \"OK\";\n            PrimaryButton.IsDefault = true;\n            SecondaryButton.IsCancel = false;\n            break;\n\n        case DialogButtons.YesNo:\n            PrimaryButton.Content = \"Ja\";\n            SecondaryButton.Content = \"Nein\";\n            SecondaryButton.Visibility = Visibility.Visible;\n            PrimaryButton.IsDefault = true;\n            SecondaryButton.IsCancel = true;\n            break;\n    }\n}<\/code><\/pre>\n\n\n\n<p>This is important because localization and UX policy remain centralized.<\/p>\n\n\n\n<p>If button wording changes later, the application does not need to update dozens of dialog call sites.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Dialog Outcome Mapping<\/h1>\n\n\n\n<p>The button click handlers map visual actions back into application semantics:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private void PrimaryButton_Click(\n    object sender,\n    RoutedEventArgs e)\n{\n    DialogOutcome =\n        PrimaryButton.Content?.ToString() switch\n        {\n            \"Ja\" => AppDialogResult.Yes,\n            _ => AppDialogResult.Ok\n        };\n\n    DialogResult = true;\n\n    Close();\n}<\/code><\/pre>\n\n\n\n<p>and:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private void SecondaryButton_Click(\n    object sender,\n    RoutedEventArgs e)\n{\n    DialogOutcome =\n        SecondaryButton.Content?.ToString() switch\n        {\n            \"Nein\" => AppDialogResult.No,\n            _ => AppDialogResult.Cancel\n        };\n}<\/code><\/pre>\n\n\n\n<p>Again, the application layer never sees WPF-native dialog primitives.<\/p>\n\n\n\n<p>Everything flows through application-defined semantics.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">One DI Registration Changes the Entire Application<\/h1>\n\n\n\n<p>The actual dialog-system swap happens in one place:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>services.AddSingleton&lt;IMessageDialogHost, CustomDialogHost>();\n\nservices.AddSingleton&lt;IDialogService, DialogService>();<\/code><\/pre>\n\n\n\n<p>Previously, this could have pointed to a different implementation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>WpfMessageDialogHost<\/code><\/pre>\n\n\n\n<p>Now it points to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CustomDialogHost<\/code><\/pre>\n\n\n\n<p>Every call site remains unchanged.<\/p>\n\n\n\n<p>That is the real value of the abstraction.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Global Error Handling Also Benefits<\/h1>\n\n\n\n<p>Chrona even routes exception handling through the same host abstraction.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class ExceptionHandler\n{\n    private readonly IMessageDialogHost _messageDialogHost;\n\n    private readonly ILogger&lt;ExceptionHandler>? _logger;\n\n    public ExceptionHandler(\n        IMessageDialogHost messageDialogHost,\n        ILogger&lt;ExceptionHandler>? logger = null)\n    {\n        _messageDialogHost = messageDialogHost;\n        _logger = logger;\n    }\n}<\/code><\/pre>\n\n\n\n<p>The safe wrapper is particularly strong:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private DialogResult SafeShowDialog(\n    string message,\n    string title,\n    DialogButtons buttons,\n    DialogIcon icon)\n{\n    try\n    {\n        return _messageDialogHost.ShowDialog(\n            message,\n            title,\n            buttons,\n            icon);\n    }\n    catch\n    {\n        \/\/ Fallback if UI is unavailable\n        return DialogResult.None;\n    }\n}<\/code><\/pre>\n\n\n\n<p>Even critical error dialogs remain inside the same architectural system.<\/p>\n\n\n\n<p>That creates consistency across the entire application.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Why This Architecture Is Valuable in Real Projects<\/h1>\n\n\n\n<p>This dialog architecture provides several long-term advantages.<\/p>\n\n\n\n<p>Design consistency improves because all dialogs follow the same visual system.<\/p>\n\n\n\n<p>Replaceability improves because rendering can evolve independently from workflows.<\/p>\n\n\n\n<p>Maintainability improves because ViewModels remain free of WPF-specific dialog details.<\/p>\n\n\n\n<p>Scalability improves because richer dialog types can be added cleanly:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>detail sections\ndanger-style confirmations\ncheckbox confirmations\nstacktrace expansions\nmulti-action dialogs<\/code><\/pre>\n\n\n\n<p>Testability improves because both <code>IDialogService<\/code> and <code>IMessageDialogHost<\/code> can be mocked or faked during tests.<\/p>\n\n\n\n<p>Most importantly, the application now owns its dialog semantics instead of delegating them to framework primitives.<\/p>\n\n\n\n<p>That is a major architectural improvement.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Possible Future Enhancements<\/h1>\n\n\n\n<p>Chrona\u2019s architecture already provides a strong foundation, but several natural extensions would fit cleanly into the current design.<\/p>\n\n\n\n<p>A <code>DialogSeverity<\/code> abstraction could support specialized destructive-action styling.<\/p>\n\n\n\n<p>Technical-detail sections could display stack traces or expandable error diagnostics.<\/p>\n\n\n\n<p>Animations such as fade or scale transitions could improve perceived UX quality.<\/p>\n\n\n\n<p>An async dialog-host API could support queued or non-modal workflows later.<\/p>\n\n\n\n<p>Visual regression screenshots could ensure dialog consistency across releases.<\/p>\n\n\n\n<p>The important point is that the architecture already supports these future evolutions cleanly because rendering and workflow semantics are separated properly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A Deep-Dive with Real Chrona Code Examples Many WPF applications begin with direct MessageBox.Show(&#8230;) calls. At first, this feels completely reasonable. A save confirmation here, an error dialog there, a warning before deletion. The implementation is fast, obvious, and immediately functional. As the application grows, however, this becomes an architectural problem. Once MessageBox.Show(&#8230;) is scattered [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,27,8,25,34],"tags":[],"class_list":["post-216","post","type-post","status-publish","format-standard","hentry","category-csharp","category-programming-principles","category-software-architecture","category-software-engineering","category-wpf"],"_links":{"self":[{"href":"https:\/\/www.fabricioruch.ch\/index.php?rest_route=\/wp\/v2\/posts\/216","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fabricioruch.ch\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fabricioruch.ch\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fabricioruch.ch\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fabricioruch.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=216"}],"version-history":[{"count":1,"href":"https:\/\/www.fabricioruch.ch\/index.php?rest_route=\/wp\/v2\/posts\/216\/revisions"}],"predecessor-version":[{"id":218,"href":"https:\/\/www.fabricioruch.ch\/index.php?rest_route=\/wp\/v2\/posts\/216\/revisions\/218"}],"wp:attachment":[{"href":"https:\/\/www.fabricioruch.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=216"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fabricioruch.ch\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=216"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fabricioruch.ch\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=216"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}