@@ -64,6 +64,8 @@ public class DialogHost : ContentControl
6464 private DialogClosingEventHandler ? _attachedDialogClosingEventHandler ;
6565 private DialogClosedEventHandler ? _attachedDialogClosedEventHandler ;
6666 private IInputElement ? _restoreFocusDialogClose ;
67+ private IInputElement ? _lastFocusedDialogElement ;
68+ private WindowState _previousWindowState ;
6769 private Action ? _currentSnackbarMessageQueueUnPauseAction ;
6870
6971 static DialogHost ( )
@@ -370,6 +372,7 @@ private static void IsOpenPropertyChangedCallback(DependencyObject dependencyObj
370372
371373 dialogHost . CurrentSession = new DialogSession ( dialogHost ) ;
372374 var window = Window . GetWindow ( dialogHost ) ;
375+ dialogHost . ListenForWindowStateChanged ( window ) ;
373376 if ( ! dialogHost . IsRestoreFocusDisabled )
374377 {
375378 dialogHost . _restoreFocusDialogClose = window != null ? FocusManager . GetFocusedElement ( window ) : null ;
@@ -395,7 +398,8 @@ private static void IsOpenPropertyChangedCallback(DependencyObject dependencyObj
395398
396399 //https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/issues/187
397400 //totally not happy about this, but on immediate validation we can get some weird looking stuff...give WPF a kick to refresh...
398- Task . Delay ( 300 ) . ContinueWith ( t => dialogHost . Dispatcher . BeginInvoke ( DispatcherPriority . Background , new Action ( ( ) => {
401+ Task . Delay ( 300 ) . ContinueWith ( t => dialogHost . Dispatcher . BeginInvoke ( DispatcherPriority . Background , new Action ( ( ) =>
402+ {
399403 CommandManager . InvalidateRequerySuggested ( ) ;
400404 //Delay focusing the popup until after the animation has some time, Issue #2912
401405 UIElement ? child = dialogHost . FocusPopup ( ) ;
@@ -405,6 +409,50 @@ private static void IsOpenPropertyChangedCallback(DependencyObject dependencyObj
405409 } ) ) ) ;
406410 }
407411
412+
413+ private void ListenForWindowStateChanged ( Window ? window )
414+ {
415+ window ??= Window . GetWindow ( this ) ;
416+
417+ if ( window is not null )
418+ {
419+ window . StateChanged += Window_StateChanged ;
420+ }
421+ }
422+
423+ private void Window_StateChanged ( object ? sender , EventArgs e )
424+ {
425+ if ( sender is not Window window )
426+ {
427+ return ;
428+ }
429+
430+ var windowState = window . WindowState ;
431+ if ( windowState == WindowState . Minimized )
432+ {
433+ _lastFocusedDialogElement = FocusManager . GetFocusedElement ( window ) ;
434+ _previousWindowState = windowState ;
435+ return ;
436+ }
437+
438+ // We only need to focus anything manually if the window changes state from Minimized --> (Normal or Maximized)
439+ // Going from Normal --> Maximized (and vice versa) is fine since the focus is already kept correctly
440+ if ( IsWindowRestoredFromMinimized ( ) && IsLastFocusedDialogElementFocusable ( ) )
441+ {
442+ // Kinda hacky, but without a delay the focus doesn't always get set correctly because the Focus() method fires too early
443+ Task . Delay ( 50 ) . ContinueWith ( _ => this . Dispatcher . BeginInvoke ( DispatcherPriority . Background , new Action ( ( ) =>
444+ {
445+ _lastFocusedDialogElement ! . Focus ( ) ;
446+ } ) ) ) ;
447+ }
448+ _previousWindowState = windowState ;
449+
450+ bool IsWindowRestoredFromMinimized ( ) => ( windowState == WindowState . Normal || windowState == WindowState . Maximized ) &&
451+ _previousWindowState == WindowState . Minimized ;
452+
453+ bool IsLastFocusedDialogElementFocusable ( ) => _lastFocusedDialogElement is UIElement { Focusable : true , IsVisible : true } ;
454+ }
455+
408456 /// <summary>
409457 /// Returns a DialogSession for the currently open dialog for managing it programmatically. If no dialog is open, CurrentSession will return null
410458 /// </summary>
0 commit comments