BB10: Cascades: Dialog and SystemDialog


I leveraged Cascades Dialogs heavily in my first BlackBerry 10 App. While there is a bit of strange behavior, the Cascades Dialog and SystemDialog controls are servicable and can help provide an exceptional user experience.

My trouble with the controls stemmed around my use of .show() and the Dialog's onFinished event. The behavior was not consistent enough for me to release the app. Solution after the jump.

References:

 

Before You Start, A Couple of things...

1- Be sure to add this line to your <ApplicationName>.pro file:

      LIBS += -lbbsystem

Without this line, none of your dialogs will work. You'll get errors at run-time when trying to use Dialogs of any flavor.

 

2- When working with SystemDialog controls, you will find that the QML Preview feature doesn't know how to handle them (Gold SDK). I just hid the QML Preview on the QML pages that used SystemDialog and relied on the Simulator/Device to check how those pages look.


3- If you want to determine if a SystemDialog's Cancel or OK buttons have been pressed, you need to compare the dialogName.result property against the number 2  or 3. Cancel == 3 and OK == 3, which is a bit backwards from what I was expecting.

 

Working with SystemDialog

The SystemDialog control requires that you add a line at the top of your qml file:

      import bb.system 1.0

Without this line, none of your System Dialogs will work at runtime. It is important to note that even with this line the QML Preview functionality will not work, so don't trust QML Preview to correctly inform you of errors (reports that SystemDialog is not a type). There's no substitute for a direct test.

Note: When I was creating my Apps I originally used the .show() method to invoke SystemDialogs. Unfortunately, I found it to be unreliable (the onFinished signal handler would not always fire). Refactoring the code to show the SystemDialogs synchronously using .exec() made things work 100% of the time. This took me many hours to troubleshoot as the event issues I was experiencing were intermittent.

For a SystemDialog to work correctly, it needs to be in an attachedObjects block with an id and an onFinished block that checks for OK / CANCEL and takes appropriate action. Here is a simple QML page that implements a button and a SystemDialog that displays a toast only when the OK button is pressed. The key sections are bolded:

import bb.cascades 1.0
import bb.system 1.0
Page {
    Container {
    Button {
       text: "Show SysDialog"
        onClicked: {
            exampleDialog.show();
        }
    }
    }
    attachedObjects: [
        SystemDialog{
              id: exampleDialog
              title: "Example Confirmation Dialog"
              body: "Confirm or Deny?"
              onFinished:{
 // This only gets called after the cancel/ok button has been pressed 
//
// Looks like cancel is 3
// OK is 2 Not quite what I expected
if(exampleDialog.result == 3){ // action is cancelled, don't do anything return; } // Show a success toast if things went well
// the .show() method works for SystemDialog
exampleToast.show(); // Use .exec() if you experience intermittent handling of onFinished! } }, SystemToast { id: exampleToast body: "Hey, Success!" } ] }

 

Working with Dialog

A Dialog differs from a SystemDialog in that it is more flexible: It lets you create something that can fill the entire screen and may not look any different from a regular QML Page. Dialog has onOpened and onClosed signal handlers that you can fill with interesting actions. If you break a Dialog out into its own QML file, you can overload the onOpened/onClosed events per instance of the Dialog control qml (in addition to the hard-coded onClosed event handler in the definition). You can open a Dialog using the .open() method. For an example of how to create your own Custom Dialog, see this example from RIM.

Note: When creating Dialogs, it's important to set a Background Color and a size so the controls in the Dialog stand-out. Without the color and size settings, the controls on QML page that call the Dialog will be visible along with the controls in the Dialog (which gets confusing).

Note 2: When you roll your own Dialog you must provide a way for the user to go 'back'. There are no default ok/cancel buttons that dismiss custom dialogs. In the example below I call the Dialogs close() method when a Dialog button is pressed.

Here's an example of how to use Dialog. A full-page Dialog is created when you press the Show Dialog button. The Dialog's OK button closes the dialog and show a Toast message. Key lines are bolded:

import bb.cascades 1.0
import bb.system 1.0
Page {
      Container {
        Button {
            text: "Show Dialog"
            onClicked: {
                exampleDialogControl.open(); // Open the Dialog
            }
        }
        }

 // The Attached Objects section holds the Dialog // along with the SystemToast that gets fired // when the Dialog is dismissed
    attachedObjects: [
        Dialog {
            id: exampleDialogControl

            onClosed: {
                // Show a toast when the Dialog has been closed
                exampleToast.show();
            }

            Container {
                // Make the dialog background 'black' so we know when it appears
                    background: Color.create (0.0, 0.0, 0.0, 1.0)

                    // Set the preferred size of the Dialog so it fills the screen
                    preferredWidth: 768
                    preferredHeight: 1280

                 Button {
                     rightMargin: 275
                     layoutProperties: StackLayoutProperties {
                         spaceQuota: 1
                     }
                     maxWidth: 200
                     text: "OK"
                     onClicked: {
                         // Close the dialog using relative access to the 'close' method
                         parent.parent.close();
                     }
                 }
            }
        },
        SystemToast {
            id: exampleToast
            body: "Dialog has been closed"
        }
    ]
}