From 267712c5689c82a261a8896db814fed8c83ff3ee Mon Sep 17 00:00:00 2001 From: Koichi Kobayashi Date: Wed, 17 Dec 2025 23:15:08 +0900 Subject: [PATCH] Improve MessageBox button focus management - Add checkIsFocused parameter to SetFocusToFirstAvailableButton method to control focus validation based on timing - Call SetFocusToFirstAvailableButton with checkIsFocused: false in OnLoaded and OnApplyTemplate to attempt early focus setting - Call SetFocusToFirstAvailableButton with checkIsFocused: true in OnContentRendered to respect developer's focus logic - Skip focus setting if focus is already on any button - Skip focus setting if focus is on a non-button control (e.g., TextBox) - Set focus to primaryButton when focus is on MessageBox itself or nowhere - Add Gallery sample demonstrating auto-focus behavior when no button or non-button control has focus --- .../DialogsAndFlyouts/MessageBoxViewModel.cs | 94 ++++++++ .../DialogsAndFlyouts/MessageBoxPage.xaml | 28 +++ src/Wpf.Ui/Controls/MessageBox/MessageBox.cs | 214 +++++++++++++++++- .../Controls/MessageBox/MessageBox.xaml | 34 ++- 4 files changed, 358 insertions(+), 12 deletions(-) diff --git a/src/Wpf.Ui.Gallery/ViewModels/Pages/DialogsAndFlyouts/MessageBoxViewModel.cs b/src/Wpf.Ui.Gallery/ViewModels/Pages/DialogsAndFlyouts/MessageBoxViewModel.cs index 940d50429..314653bec 100644 --- a/src/Wpf.Ui.Gallery/ViewModels/Pages/DialogsAndFlyouts/MessageBoxViewModel.cs +++ b/src/Wpf.Ui.Gallery/ViewModels/Pages/DialogsAndFlyouts/MessageBoxViewModel.cs @@ -29,4 +29,98 @@ private async Task OnOpenCustomMessageBox(object sender) _ = await uiMessageBox.ShowDialogAsync(); } + + [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "relay command")] + [RelayCommand] + private async Task OnOpenThreeButtonMessageBox(object sender) + { + var uiMessageBox = new Wpf.Ui.Controls.MessageBox + { + Title = "Confirmation", + Content = "Do you want to save your changes before closing?", + PrimaryButtonText = "Save", + SecondaryButtonText = "Don't Save", + CloseButtonText = "Cancel", + DefaultFocusedButton = Wpf.Ui.Controls.MessageBoxButton.Secondary, + }; + + var result = await uiMessageBox.ShowDialogAsync(); + _ = MessageBox.Show($"You selected: {result}", "Result"); + } + + [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "relay command")] + [RelayCommand] + private async Task OnOpenMessageBoxWithFocusableContent(object sender) + { + var textBox = new System.Windows.Controls.TextBox + { + Text = "Type something here...", + Margin = new System.Windows.Thickness(0, 8, 0, 0), + }; + + var uiMessageBox = new Wpf.Ui.Controls.MessageBox + { + Title = "Input Required", + Content = new System.Windows.Controls.StackPanel + { + Children = + { + new System.Windows.Controls.TextBlock + { + Text = "Please enter your name:", + TextWrapping = System.Windows.TextWrapping.Wrap, + }, + textBox, + }, + }, + PrimaryButtonText = "OK", + SecondaryButtonText = "Cancel", + DefaultFocusedButton = Wpf.Ui.Controls.MessageBoxButton.Primary, + }; + + var result = await uiMessageBox.ShowDialogAsync(); + if (result == Wpf.Ui.Controls.MessageBoxResult.Primary) + { + _ = MessageBox.Show($"Hello, {textBox.Text}!", "Greeting"); + } + } + + [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "relay command")] + [RelayCommand] + private async Task OnOpenMessageBoxWithIcons(object sender) + { + var uiMessageBox = new Wpf.Ui.Controls.MessageBox + { + Title = "Warning", + Content = "This action cannot be undone. Are you sure you want to continue?", + PrimaryButtonText = "Yes, Continue", + SecondaryButtonText = "No, Cancel", + PrimaryButtonIcon = new Wpf.Ui.Controls.SymbolIcon + { + Symbol = Wpf.Ui.Controls.SymbolRegular.Warning24, + }, + DefaultFocusedButton = Wpf.Ui.Controls.MessageBoxButton.Secondary, + }; + + _ = await uiMessageBox.ShowDialogAsync(); + } + + [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "relay command")] + [RelayCommand] + private async Task OnOpenMessageBoxWithAutoFocus(object sender) + { + // DefaultFocusedButton is not set, so focus will automatically be set to primaryButton + // when no button has focus and no non-button control has focus + var uiMessageBox = new Wpf.Ui.Controls.MessageBox + { + Title = "Auto Focus", + Content = "This MessageBox will automatically set focus to the primary button when no button or non-button control has focus.", + PrimaryButtonText = "OK", + SecondaryButtonText = "Cancel", + // DefaultFocusedButton is intentionally not set + }; + + var result = await uiMessageBox.ShowDialogAsync(); + _ = MessageBox.Show($"You selected: {result}", "Result"); + } } diff --git a/src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/MessageBoxPage.xaml b/src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/MessageBoxPage.xaml index 577f8f3a8..7c1c23f32 100644 --- a/src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/MessageBoxPage.xaml +++ b/src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/MessageBoxPage.xaml @@ -36,5 +36,33 @@ CommandParameter="{Binding RelativeSource={RelativeSource Self}, Mode=OneWay}" Content="Open custom MessageBox" /> + + +