WPF: MessageBox.Show in Window.OnClosing crash on restore window

0

I have simple WPF application with a main window and a child window. The child window should ask for confirmation on close.

  public partial class MainWindow : Window
  {
    Window childWindow;

    public MainWindow()
    {
      InitializeComponent();
      Loaded += MainWindow_Loaded;
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
      childWindow = new Window();
      childWindow.Owner = this;
      childWindow.Closing += ChildWindow_Closing;
      childWindow.Show();
    }

    private void ChildWindow_Closing(object sender, CancelEventArgs e)
    {
      MessageBox.Show(childWindow, "Close child window?");
    }
  }

When confirmation dialog is shown if click "Show desktop" on taskbar and then click "Show open windows", app will be crashed with exception:

System.InvalidOperationException occurred
  HResult=0x80131509
  Message=Cannot set Visibility to Visible or call Show, ShowDialog, Close, or WindowInteropHelper.EnsureHandle while a Window is closing.
  Source=PresentationFramework
  StackTrace:
   at System.Windows.Window.VerifyNotClosing()
   at System.Windows.Window.CoerceVisibility(DependencyObject d, Object value)
   at System.Windows.DependencyObject.ProcessCoerceValue(DependencyProperty dp, PropertyMetadata metadata, EntryIndex& entryIndex, Int32& targetIndex, EffectiveValueEntry& newEntry, EffectiveValueEntry& oldEntry, Object& oldValue, Object baseValue, Object controlValue, CoerceValueCallback coerceValueCallback, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, Boolean skipBaseValueChecks)
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
   at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
   at System.Windows.Window.UpdateVisibilityProperty(Visibility value)
   at System.Windows.Window.WmShowWindow(IntPtr wParam, IntPtr lParam)
   at System.Windows.Window.WindowFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at System.Windows.Interop.HwndSource.PublicHooksFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)

If replace owner of MessageBox dialog to the main window (to "this"), the exception isn't occurs.

What here can be wrong?

.net
wpf
windows-10
asked on Stack Overflow Jul 21, 2017 by quio

1 Answer

1

Can you post your XAML code? See below what I have in MainWindow.xaml, copied your code into MainWindow.cs and the app complies and runs ok.

<Window x:Class="WpfApp2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp2"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>

</Grid>

Sorry this is not much of a help, can't reproduce your exception.

Edit: Another thought, you might try using

childWindow.ShowDialog();

Further edit:

Based on your comment I found what causes the exception. Prior using the 'Show Desktop' function, there are two app windows opened in the taskbar. Subsequently, when trying to restore the app from taskbar, the child window is no longer visible. It seems that Windows makes a judgement call, losing the closing child window in advance. So when you click on the main window thumbnail, the app tries to bring into view the parent window but is unable to set its visibility, whilst there is its child in closing process.

There may be few approaches to this, but hiding the child window while closing may be one of them. Alternatively you could temporarily hide the main window instead, this also prevents the exception. The former solution gives the visibility back to the parent window, assuming the child window will be closed (if not set it to visible again), the latter leaves the child window the only visible window and it forces Windows to show its thumbnail in taskbar.

private void ChildWindow_Closing(object sender, CancelEventArgs e)
        {
            childWindow.Visibility = Visibility.Hidden;
            MessageBox.Show(childWindow, "Close child window?");
        }

or

private void ChildWindow_Closing(object sender, CancelEventArgs e)
        {
            Visibility = Visibility.Hidden;
            MessageBox.Show(childWindow, "Close child window?");
            Visibility = Visibility.Visible;
        }
answered on Stack Overflow Jul 21, 2017 by RWo • edited Jul 22, 2017 by RWo

User contributions licensed under CC BY-SA 3.0