Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MainWindow.Closing event not always raised in Silverlight 4 OOB app

I've made a rather complex Silverlight 4 out-of-browser application. One of my main view models adds an event handler to the Application.Current.MainWindow.Closing event. This works fine when the application is initially run. It is able to cancel the close operation.

However, sometimes after performing operations like showing and closing a ChildWindow, the MainWindow's Closing event is no longer calling my handler.

In the debugger, I added a watch to the MainWindow's underlying closing event delegate. It's not null before showing the ChildWindow. Then sometimes after the ChildWindow is closed the delegate is null. This is explains why my handler is not called any more. But why is this delegate getting nulled? And why is it only happening occasionally? My application is not unbinding my event handler at any point.

This is the delegate I'm watching:

System.Windows.Application.Current.MainWindow.m_closingEvent

Other stuff: I'm using Caliburn Micro

like image 909
Andrew Davey Avatar asked Aug 28 '10 16:08

Andrew Davey


3 Answers

I had the exact same problem. We have a large silverlight application running OOB.

For some reason the m_ClosingEvent was nulled after running for a while. I have not been able to find the cause of this issue but I think it may have something to do with us changing the root visual or all the child windows we show.

I´m using a class ApplicationWrapper.

public class ApplicationWrapper : IApplicationWrapper
{
  public void Initialize()
  {
    HookCloseEvent(true);
  }
  private void HookCloseEvent(bool hook)
  {
    if (hook && IsRunningOutOfBrowser)
    {
      Application.Current.MainWindow.Closing += OnClosing;
    }
    else
    {
      if (IsRunningOutOfBrowser)
      {
        Application.Current.MainWindow.Closing -= OnClosing;
      }
    }
  }
  private void OnClosing(object sender, ClosingEventArgs e)
  {
    InvokeClosing(e);
  }

... etc.. 
}

And the InvokeClosing method was never called. But when I changed it to

public class ApplicationWrapper : IApplicationWrapper 
{
  private Window _mainWindow;

  public void Initialize()
  {
    if(IsRunningOutOfBrowser)
    {
      _mainWindow = Application.Current.MainWindow;
    }
    HookCloseEvent(true);
  }

  private void HookCloseEvent(bool hook)
  {
    if (hook && IsRunningOutOfBrowser)
    {
      _mainWindow.Closing += OnClosing;
    }
    else
    {
      if (IsRunningOutOfBrowser)
      {
        _mainWindow.Closing -= OnClosing;
      }
    }
  }

  private void OnClosing(object sender, ClosingEventArgs e)
  {
    InvokeClosing(e);
  }

... etc... 
}

The m_ClosingEvent isn´t nulled.

So, try to just store the "initial" MainWindow in a field and check if that solves your problem.

like image 120
Truls Clauss Avatar answered Sep 22 '22 12:09

Truls Clauss


Instead of hooking to the event, why not register a service instead? Create a class that implements IApplicationService and IApplicationLifetimeAware. The latter gives you an "onexiting" and "onexited" pair of events. You place the service in the application by pointing to it in a section called in your App.xaml. I've used this for many projects and never had an issue with the exiting methods not being called.

like image 27
Jeremy Likness Avatar answered Sep 21 '22 12:09

Jeremy Likness


Ok, after pulling out my hair and many false starts I finally found the answer - it seems to be a known bug with the Closing event, OOB and ChildWindows open/closes...

The trick is to store a static reference to the Main Window:

public MainPage()
{
    InitializeComponent();
    Loaded += MainPage_Loaded;
}

private void MainPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
    //you have to store this to work around the bug
    //http://forums.silverlight.net/forums/p/185664/424174.aspx
    _mainWindow = App.GetApp.MainWindow;

    App.GetApp.MainWindow.Closing += (s, e1) =>
    {
        if (UIUtilities.ShowMessage("Would you like to exit AMT Mobile?", "Exit Application", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
        {
            e1.Cancel = true;
        }
    };
}
like image 25
Rodney Avatar answered Sep 21 '22 12:09

Rodney