Xojo Terminates threads when application is quit

Then use a sheet window :wink:
In a CancelClose event, you can close all the other windows, so each show a sheet window (not blocking the UI).
Drawback: this won’t work with Windows or Linux…

Or, do it otherwise:
In the first occurring CancelClose event, show the “Would you like to save changes for this window?” dialog. Wait for the user to answer.
In a property of the window (e.g. UserAnswer As MessageDialogButton), store the answer of the dialog, close the next window and return true.
The second window then shows the same message box (and so on for all windows).
Once all windows have asked to save changes (you know that by checking if UserAnswer is nil or not), close again each window (now, every window knows the user’s choice and can save or not).

A slightly different method, common on Mac, would be to first show a global message: “Do you want to save changes to all windows before closing?” with buttons {“Save all”, “Review one by one” and “Cancel”}.
“Review one by one” would then ask for each window; the user may choose “Save all” only once to be not bothered by many dialogs.

@MarkusR That’s pretty much what I’m doing.

@Arnaud_N I am using a sheet window to ask about closing. However, Xojo only performs one CancelClose at a time. It doesn’t move on to the next one until the first returns, that way it can check for a user Cancel not do the rest of the Windows.

I’ve taken your idea and worked up something that works very well.

The following in the App.CancelClose method. I’ve created my own AskCancelClose method which asks the standard Don’t save, Cancel, Save message. It checks that they didn’t respond with a Cancel before looping around to the next form. Each window remembers the response provided and if Close is called uses it as the response to the true CancelClose event.

Function CancelClose() Handles CancelClose as Boolean
  Var nWindow As Integer
  Var nWindows As Integer = App.WindowCount
  Var aWindows() As CSW
  Var NoneChanged As Boolean = True
  
  For nWindow = 0 To nWindows - 1
    If App.Window( nWindow ) IsA CSW Then
      aWindows.Add CSW( App.Window( nWindow ) )
      If App.Window( nWindow ).Changed Then
        NoneChanged = False
      End If
    End If
  Next
  
  ' If none of the windows needed saving or there where no CSW windows open
  If NoneChanged Or aWindows.LastIndex = -1 Then
    ' Then just let the application Quit In the normal way
    Return False
    
  Else
    ' Now ask each window what it wants to do about closing. If any return cancel cancel out of the CancelClose event without action
    For nWindow = 0 To aWindows.LastIndex
      aWindows( nWindow ).AskCancelClose
      If aWindows( nWindow ).AskCancelCloseResponse = CloseCancelDialog.Cancel Then
        '
        ' Clear all the windows we've done so far, so they actually ask when the window is next closed
        '
        For nWin As Integer = 0 To nWindow
          aWindows( nWindow ).AskCancelCloseResponse = -1
        Next
        Return True
      End If
    Next
    Return False
    
  End If
End Function

The true Window.CancelClose event as follows:

#Pragma Unused appQuitting
If Changed Then
  If AskCancelCloseResponse = -1 Then
    Var oDialog As New CloseCancelDialog
    Select Case oDialog.ShowModalWithin( Self )
      
    Case CloseCancelDialog.Cancel
      ' They pressed Cancel on the Closing dirty window dialog
      Return True
      
    Case CloseCancelDialog.Save
      ' They pressed save on the Closeing dirty window dialog
      If SaveTable( False, True, True ) Then
        Return False
      Else
        ' They pressed the cancel button on the SaveAs Dialog so we're done with Quitting
        Return True
      End If
      
    Case CloseCancelDialog.DontSave
      ' They pressed don't save, continue to close and quit if that's whats happening
      Return False
      
    End Select
    
  Else
    If AskCancelCloseResponse = CloseCancelDialog.Save Then
      ' They pressed save on the Closeing dirty window dialog
      If SaveTable( False, True, True ) Then
        Return False
        
      Else
        Return True
        
      End If
      
    Else
      Return False
      
    End If
  End If
Else
  Return False
  
End If

AskCancelClose method:

If Changed Then
  Var oDialog As New CloseCancelDialog
  AskCancelCloseResponse = oDialog.ShowModalWithin( Self )
Else
  AskCancelCloseResponse = CloseCancelDialog.DontSave
End If

with AskCancelCloseResponse being a property of the window.

All the windows ask right away, one by one. The App.CancelClose then returns False in the standard way closing all the windows, responding without asking from th prior answers.

1 Like