Friday, April 20, 2012

WPF ribbonwindow - doubleclicking application icon causes Shutdown

A WPF application whose main window is created from WPF RibbonWindow shows different behavior between closing right-top close (X) button and doubleclicking application icon on the left-top side.

When clicking right-topmost Close button, the window is closed and developer can cancel window close in window's Closing event handler by settting e.Cancel to true. Here is a callstack example when the Close button is clicked. Alt-F4 has the same effect as clicking Close button.

  Console.MainWindow.WindowConsole_Closing(object sender, System.ComponentModel.CancelEventArgs e) Line 679 C#
  PresentationFramework.dll!System.Windows.Window.OnClosing(System.ComponentModel.CancelEventArgs e) + 0x8c bytes 
  PresentationFramework.dll!System.Windows.Window.WmClose() + 0x96 bytes 
  .............
  WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) + 0xc1 bytes 
  WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) + 0x49 bytes 
  WindowsBase.dll!System.Windows.Threading.Dispatcher.Run() + 0x4c bytes 
  PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) + 0x17 bytes 
  PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) + 0x6f bytes 
  PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window) + 0x26 bytes 
  PresentationFramework.dll!System.Windows.Application.Run() + 0x1b bytes 
  Mitutoyo.QCCAT.Console.exe!Mitutoyo.QCCAT.Console.App.Main() + 0x5e bytes Unknown
  

If a user doubleclicks leftmost application icon, the application initiates app shutdown and send window close signals to all windows. But, if window close event handler cancels, it will not be honored and simply ignored and keep going for shutdown. This means develoepr cannot cancel window close, no matter what. Here is the call stack when app icon is doubleclicked. You can see Application.DoShutdown() in the middle.

> Console.MainWindow.WindowConsole_Closing(object sender, System.ComponentModel.CancelEventArgs e) Line 679 C#
  PresentationFramework.dll!System.Windows.Window.OnClosing(System.ComponentModel.CancelEventArgs e) + 0x8c bytes 
  PresentationFramework.dll!System.Windows.Window.WmClose() + 0x96 bytes 
  PresentationFramework.dll!System.Windows.Window.InternalClose(bool shutdown, bool ignoreCancel) + 0xa1 bytes 
  PresentationFramework.dll!System.Windows.Application.DoShutdown() + 0x1b6 bytes 
  PresentationFramework.dll!System.Windows.Application.ShutdownImpl() + 0x1c bytes 
  PresentationFramework.dll!System.Windows.Application.ShutdownCallback(object arg) + 0x5 bytes 
  ...........
  [Managed to Native Transition] 
  WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) + 0xc1 bytes 
  WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) + 0x49 bytes 
  WindowsBase.dll!System.Windows.Threading.Dispatcher.Run() + 0x4c bytes 
  PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) + 0x17 bytes 
  PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) + 0x6f bytes 
  PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window) + 0x26 bytes 
  PresentationFramework.dll!System.Windows.Application.Run() + 0x1b bytes 
  Mitutoyo.QCCAT.Console.exe!Mitutoyo.QCCAT.Console.App.Main() + 0x5e bytes Unknown
  

One can work around this problem by overwriting Applications.Close behavior. Here is a code snippet.

 public partial class MainWindow : RibbonWindow
 {
    public MainWindow()
    {
       InitializeComponent();
       this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, ApplicationCloseExecuted)); 
    }
          
    private void ApplicationCloseExecuted(object sender,
             ExecutedRoutedEventArgs e)
    {
       this.Close();
    }

    private void Window_Closing(object sender, CancelEventArgs e)
    {
       if (MsgBox("Sure?") == true) {
          Terminate();
       }
       else {
          e.Cancel = true; // cancel window close
       }
    }
 }

No comments:

Post a Comment