This is a continuation of the XAML App Review. The articles in this series are collected together here: Jeremy Bytes - Downloads.
Last time, we took a look at the form manager -- how the different forms/pages are swapped in and out of the client area. This time, we'll be looking at a Popup Message implementation that lets us give information to the user that doesn't require user interaction. But first, let's explore some cool things we can do with the form manager.
Cool Ideas for the Form Manager
In Part 2, we saw how the form manager works with the verdict that it got the job done. But what if we were to think about some cool things we could do to enhance the form swapping?
First, we could work on the transitions between forms. The form manger in its current state simply removes one form and replaces it with another. We could add some sliding animation that would slide the new form in over the old form. Or we could make it like a filmstrip where the old form slides out as the new form slides in.
But let's take this step further: because we have all of the instantiated forms in memory (in the form controllers list of forms), we could keep them visually available as well. We could implement a "swipe" interface that would allow the users to move easily from one form to another. We would also need to add something visually (probably at the top or bottom of the screen) so that the user could have a thumbnail of the screens to make it easier to navigate.
In this scenario, we may want to instantiate all of the forms up front (which would be practical only for an application with a small number of forms, like our sample). This would pre-populate the filmstrip and make things operate very smoothly. If we were to do something like this, we would want to take some hints from the mobile world: load up the screen the user sees first, and then load the others in the background. This ensures that the application feels fast to the user.
These are just some things to think about. The form manager gives us a good jumping off point for much more interesting ways of presenting the application. The UX designers can take it from there.
Often in applications, we have information to give to the user that the user does not need to act on; it is strictly informational. An example is a "Save Complete" message. This lets the user know that the operation completed successfully, but we don't need him to take any action on it. For this type of message, modal dialogs are not appropriate (ex: MessageBox.Show) because they require the user to click the "OK" button. If we have a number of these types of messages (or saves are frequent), then this only serves to annoy the user. Instead, we should display this information without requiring interaction.
In the XAML Tips application, we have a Popup Message screen that shows this type of thing in action (as a reminder, you can run this application live from here: Jeremy Bytes - Downloads):
This message only displays temporarily. In this case, it stays visible for 5 seconds and then automatically goes away. It does this using a simple fade-in/fade-out animation that will draw the user's eye toward the message without being too distracting (hopefully). The message also contains a close button (the "X") so that the user can force the message to go away sooner. But no action is required.
This functionality is implemented in the MainPage. First, let's look at the XAML:
This is a simple border that contains 2 text blocks: one for the "X", and one for the message. Here's a close-up of the output to compare to the XAML:
The important bit to notice about the XAML is the Opacity of the Border is set to "0". This means that this element is normally completely transparent. The XAML also contains an animation storyboard (in the Resources section) that animates the Opacity property:
This will animate the Opacity from 0 to 1 (from transparent to opaque). The code-behind the MainPage contains the methods that fire the animation:
The MessagePopUp method is called to show the popup message. The parameters are the message and the number of seconds that the message should be shown. We can see these parameters used to set the text box text and the animation duration. Notice that the animation AutoReverse property is set to true. This will make the border go from transparent to opaque and then back to transparent. The Completed event handler will ensure that the animation is stopped when we are done. Finally, the method starts the animation.
The PopUpAnimation_Completed event handler stops that animation (this needs to be done as a "clean up" step). The CloseText_MouseLeftButtonDown event handler does the same thing. This handler is hooked up to the "X" on the page. When the "X" is clicked, the animation is stopped immediately, and the opacity returns to the "0" state.
All of this is in the MainPage.xaml and MainPage.xaml.cs files. Because the other forms are all docked into the MainPage (or more precisely, they are parented by a control on MainPage), the forms have access to the MessagePopUp method.
Here is the code from PopupMessagePage that is called when the button is clicked:
First, we get a reference to the MainPage by looking at the application's RootVisual element. Once we have this, we can call the MessagePopUp with the message and duration parameters. This code has a potential issue: if the pg variable is null, then the call to MessagePopUp will throw an exception. In the case of this particular application, it's not a problem since we know that the only way these forms will be used is docked to the MainPage. But it's still not a good practice; we should be programming more defensively. Here, we can simply check "pg" for null before making the MessagePopUp call.
The popup message is a great way to show information to the user. This is especially true in Silverlight where all of our data access calls are asynchronous. For example, when we click a "Save" button, it makes an asynchronous call into our data store to persist the information. The user can continue to use the application. When the asynchronous call is complete, the callback can use the MessagePopUp to confirm to the user that the item was saved successfully. This is a great way to let the user continue using the application while the background processes are running, and then letting the user know when the process is complete. (Obviously, if the process fails, we need to handle things a bit differently; but this is a good "success" scenario.)
There is an issue with this implementation that needs a work-around. Even though the popup message is transparent most of the time, it is still "on top" of everything else. This means that if you have a text box or button that are "under" the popup message area, they will be visible, but the user cannot click them. The workaround is to not have any interactive controls directly under the popup message area. Controls that don't require interaction (like text blocks, images, etc.) show up fine in that area. As a side note, we use this behavior to our advantage in the Please Wait message that we'll be looking at next time.
Overall, this implementation is effective. As an enhancement, I would like to have the animation behave more like "toast" messages that slide up and slide down (or vice versa depending on whether it is on the top or bottom of the screen). That requires a bit more work on the animation storyboards and visuals. This would also take care of the issue noted in the "Cons" section because the popup message would be mostly 0 height and not actually on top of anything else.
As noted above, we also need some better error handling. Part of this may be how the form references the MainForm. Some of this could be handled in a ViewModel if we were to use the MVVM pattern. As you've probably noticed, this application is not using MVVM; we'll talk about this a bit in Part 5.
As with all visual elements in XAML, there are a lot of different implementations that we could use here. The key to this type of message is that we don't block the user from continuing with his work, and we don't require him to click an "OK" button. Sometimes we need the user to acknowledge something but many times we don't.
Next time, we'll take a look at the Please Wait message. This is a way of creating synchronous behavior in our application even when Silverlight is forcing the asynchronous action behind the scenes. We'll consider some situations where this is appropriate and see how we can make the sure the application does not appear to be "locked up".