0

With the advent of the non-blocking MessageDlg in XE7, it seems that it's now impossible to conditionally prevent the app. from closing as we do in Windows (or did in XE5):

procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
    CanClose := False;
    FCanClose := False;
    FMX.Dialogs.MessageDlg('Exit?'
        ,
        TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
          procedure(const AResult: TModalResult)
          begin
            if AResult = mrYes then
              FCanClose := True;
          end
    );
    CanClose := FCanClose;

end;

The MessageDlg (and the anonymous procedure) is called only AFTER the form has already closed, thereby defeating the object. Oh, and in case you're wondering why I'm using an FCanclose, it's because I got a compiler error about "not able to capture Canclose" in the anonymous procedure.

Now the other possibility I tried, was to put the MessageDlg in the FormKeyUp event handler and trap the vkHardwareBack.

procedure TfrmMain.FormKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char;
  Shift: TShiftState);
var
  FService: IFMXVirtualKeyboardService;
begin
  if Key = vkHardwareBack then
  begin
    TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyBoardService,
        IInterface(FService));
      if (FService <> nil) then
      begin
        if (TVirtualKeyBoardState.Visible in FService.VirtualKeyBoardState) then

        else
        begin
          FMX.Dialogs.MessageDlg('Exit?'
          ,
          TMsgDlgType.mtConfirmation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0,
          procedure(const AResult: TModalResult)
          begin
            if AResult = mrYes then
              Key := 0; // prevent exit, if Key could be "captured"
          end
          );
        end;
      end;
end;

But once again, the MessageDlg is only called AFTER the FormKeyUp eventhandler has finished executing, once again rendering the key setting useless! (if it could be "captured", that is)

How do I give the user the option to not close the app because maybe they hit the backbutton once too often, or perhaps because there is some task they need to complete before they can be allowed to exit?

Freddie Bell
  • 2,186
  • 24
  • 43

1 Answers1

6

The field FCanClose is initialized with False. After the first call of CloseQuery CanClose will be set to False and the MessageDialog will show up. After confirming the dialog with mrYes FCanClose will be set to True and the Close method of the form is called again. Now, while FCanClose is True there will be no dialog and CanClose is set to True and the form will close.

procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if not FCanClose then
    FMX.Dialogs.MessageDlg(
      'Exit?',
      TMsgDlgType.mtConfirmation, 
      [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 
      0,
      procedure(const AResult: TModalResult)
      begin
        if AResult = mrYes then
        begin
          FCanClose := True; // set the field value
          Close; // call close again
        end;
      end );

  CanClose := FCanClose;
end;
Sir Rufo
  • 18,395
  • 2
  • 39
  • 73