Showing posts with label Code Review. Show all posts
Showing posts with label Code Review. Show all posts

Saturday, April 14, 2012

XAML App Review - Part 5: MVVM and Wrap Up

This is a continuation of the XAML App Review. The articles in this series are collected together here: Jeremy Bytes - Downloads.

Last time, we saw the Please Wait screen which turns asynchronous calls into synchronous application behavior.  This time, we'll take a look at the MVVM pattern and how it relates to our sample application.

The Model-View-ViewModel (MVVM) Pattern
As you've probably noticed, the XAML Tips application does not use the Model-View-ViewModel (MVVM) pattern.  We won't go in depth on the pattern (we'll save that for another day).  We'll just take a look at some basics, the the reasons for using the pattern, and why we did not use the pattern here.

First the basics: MVVM is a design pattern that is concerned with the presentation layer of the application.  As noted by the name, it consists of 3 parts.  The Model consists of the business layer of the application (and everything below that).  We can think of this as everything except for the presentation.  The View consists of the UI elements (the XAML) that the users sees and interacts with.  The ViewModel is the goo that holds the Model and View together.  It takes advantage of the flexible databinding model that is available in the XAML world.  Basically, the XAML elements are databound to properties and objects in the ViewModel (the View never directly interacts with the Model).  The ViewModel handles the communication with the Model to populate these objects and to make method calls through to the Model.

Now that we have seen the parts of the MVVM pattern, let's take a look at why we would want to use the pattern.  The benefits of the pattern are to resolve 3 main problem spaces:
  • Problem Space: Mixture of Presentation and Business Logic
    MVVM encourages good separation between the presentation and business layers of the application.
  • Problem Space: Unit Testing of the Presentation Layer is Difficult
    MVVM makes it easier to unit test the presentation layer by separating the UI elements (the View) from the presentation functionality (the ViewModel).
  • Problem Space: File Sharing between Designers and Developers
    MVVM makes it easier to manage source code because the designers can be working with the XAML files (the View) while the developers work with the code files (the ViewModel and Model).
All design patterns have both benefits and costs.  There are 2 primary costs of the MVVM pattern:
  • Cost: Added Complexity
    MVVM adds complexity to the presentation layer that requires an additional learning curve by the development team.
  • Cost: Errors Move from Compile Time to Run Time
    MVVM works through the flexible databinding mechanism in Silverlight/XAML.  Incorrect databinding does not cause compile-time errors, so a number of errors are moved to run time.
Again, this is just a quick overview of MVVM.  MVVM is a very important and useful pattern in the XAML world.  We'll take an in-depth look at this pattern in a future article.

Why No MVVM in XAML Tips?
There are a couple of reasons why the MVVM pattern was not used in the XAML Tips application (or more correctly, in the application that XAML Tips is based on).

First, the application would not take advantage of the benefits of the pattern.  Let's take a look at each of the benefits:
  • Mixture of Presentation and Business Logic
    As mentioned in the Introduction, we had been using CSLA as a business layer framework in other applications.  Because of this, we already had the separation of concerns between the UI and business layer.  As such, we already had a resolution for this problem space.  Note: CSLA is MVVM compatible (it really deals with the "M" part of the pattern), and there are helper objects to make working with the pattern easier.
  • Unit Testing of the Presentation Layer is Difficult
    At the time the application was written, we were not making extensive use of unit testing.  The testing that we did have was focused on the business layer.  In addition, the UI for this application was fairly simple (primarily CRUD operations).  As such, we were not doing unit testing of the presentation layer.
  • File Sharing between Designers and Developers
    For this application, the designer and developer were the same person (me).  As such, we would not get the benefit of the separation of the XAML and code files.
Second, as noted in the Introduction, this application was a first Silverlight production application.  We were trying to limit the number of new/unknown parts to the development.  Since we did not fully understand the environment we were working in, it would be difficult to correctly implement the MVVM pattern.  We would most likely have had several design issues and/or kludges to get things to work as expected.  Now that we have the basics under our belt, we are better equipped to understand what a good implementation of MVVM would look like.

MVVM is a Good Pattern
It's hard to do any work in the XAML world without running across the MVVM pattern.  It is a good pattern, and I recommend its use.  But as with all patterns, there are benefits and costs.  We should make sure that the benefits outweigh the costs in our implementation.

If I were to re-write this application, I would most likely use MVVM.  We could take advantage of the pattern to abstract some items (such as our Please Wait functionality) and to use databinding more extensively.

The Good, the Bad, and the Ugly
We've taken a look at a lot of different parts of our XAML Tips UI implementation.  Some things we like, some things need some changes, and some things need complete re-writes.  Here's where we ended up:

Overall Operation
The application behaves like a WinForms application (which is not necessarily bad).  But we can be more creative with our presentation based on the flexibility that XAML offers us.

Look and Feel
Having the style and brush resources centralized in the App.xaml is good.  This allows us to change the overall look of the application by making just a few changes.  The gradient design looks dated; we should look at updating the colors and styles to match current design sensibilities.

ICloseQueryable
The ICloseQueryable interface may be better served with a base class that exposes a Closing event.  Alternately, we could add an auto-save functionality that would make this unnecessary.

Form Manager
The form manager needs some better error handling in managing which form is docked in the client area (adding and removing the children from the UI element).  Also, we can look at a filmstrip-type interface that would change the way that the user interacts with multiple forms.

Popup Message
The popup message is a good implementation.  We can make this a little more visually interesting by changing the animation to behave more like "toast".

Please Wait Screen
There are too many problems with the Please Wait screen to use it as-is.  The risk is that the entire application will be locked up if the screen is not hidden appropriately.

MVVM
While the application did not use the MVVM pattern for the reasons stated above, we should reconsider this (based on being comfortable with the environment and understanding the pattern).  The ViewModel could be used to enhance the operation of the form controller, the popup message, and (most importantly), the Please Wait functionality.

Wrap Up
There were quite a few decisions made when this application was originally created.  Some of those decisions have stood up to the test of time, and some of those decisions have not.  The important part is that we take the time to go back to applications that we've created and take a look at them with a critical eye.  By reviewing what we did, we can pick out the parts that are good, the parts that need some improvement, and the parts that really need to be thrown out.

Our creations are never perfect.  And that's okay.  As long as we can admit that things can be done better, we can learn from our experience and move on.  If we ever think that an application is perfect (and refuse to budge from that view), then we've just slipped into the mode of being stuck in our ways.

Application development is about continuous learning ("development", if you will).  Let's keep learning and keep moving forward.

Happy Coding!

Friday, April 13, 2012

XAML App Review - Part 4: Please Wait Screen

This is a continuation of the XAML App Review. The articles in this series are collected together here: Jeremy Bytes - Downloads.

Last time, we saw the Popup Message that lets us give information to the user that doesn't require user interaction.  This time, we'll take a look at the Please Wait screen; this lets us turn asynchronous behavior into synchronous behavior.  Before we look at the implementation, let's think about why we would want to do this.

Why Have a "Please Wait" Screen?
Silverlight is asynchronous by nature.  This means that anytime we are going to our data store, we must use asynchronous calls.  This took me a while to get used to, but I understand why this decision was made.  At its core, Silverlight is a browser plug-in.  This means that if you "hang" Silverlight, you end up hanging the entire browser.  This would not make for good user experiences.  Instead, Silverlight does most of its work asynchronously and the browser remains responsive.

As developers, this means that we need to adapt the way that we have been programming to accommodate this behavior.  In the WinForms world, we primarily make synchronous calls where the applications waits for an action to complete (the exception is when we explicitly fire off an async call when the application calls for it).

In Part 3, we saw how the popup message can help us with this.  If we fire off an async call (such as to Save an object), the user can continue to use the application, and then we can inform him of the success after the call returns.  The best user experience is one where these asynchronous calls run quickly.  If they run quickly enough, then the user will not see any difference between synchronous and asynchronous behavior (because we're doing our jobs correctly).

But there are times when we can't make something run faster (such as when we are hampered by a database call we have no control over), and we need to keep the user from interacting with the application until the process is complete.

For example, let's say that we have a report that takes 30 seconds to run.  In the simple UI that was created for the application, we are simply filling a grid with data that is returned from the database (this is in the original application, not our XAML Tips replica).  We need to keep the user from doing a couple of things until the data is returned.  First, we need to keep him from clicking the "Run Report" button again; this would end up firing off another asynchronous call, and we just end up slowing everything down.  Next, we need to keep him from closing the current form since this is where the data will be displayed after it is returned.

Rather than enabling/disabling individual controls and functions (which may actually be the better answer), I created a "Please Wait" screen that prevents the user from interacting with the application until the asynchronous call returns.  This is a simple solution, but it has some pretty serious problems that need to be addressed.

"Please Wait" Screen in Action
First, let's see how the screen works.  As a reminder, you can run the application from here: Jeremy Bytes - Downloads.  If we run the application, and select "Please Wait" from the menu, we get the following screen:


This screen is here to simply show the Please Wait screen in action.  As mentioned above, it is designed to be used with asynchronous calls.  When we click the "Show Please Wait" button, we see the Please Wait message:


Notice that the message (and the semi-transparent background) covers the entire screen.  This prevents us from clicking any buttons or menu items.  Also, the "Please Wait" text is animated so that it fades in and out while the message is in place.  This (hopefully) gives the user the impression that the application is still responsive and is not hung.

The implementation is fairly straight forward.  The MainPage has the following XAML:


This is a simple border with a semi-transparent background.  Right in the middle is a text block with the "Please Wait" text.  The trick here is that the Height and Width properties on the border are each set to 1.  This means that by default, the element has almost no size.

The screen is shown or hidden with the PleaseWait method (in the MainPage.xaml.cs):


When the parameter is set to "true", the screen is shown.  This is done by setting the border's Height and Width properties so that the element covers the entire screen.  Next, it fires off the text animation that fades the message in and out.  The storyboard for the animation is in the Resources section of MainPage:


This just animates the opacity of the text from 1 (the default) to 0 (transparent).  In conjunction with the method, AutoReverse will send it from 1 to 0 and back to 1.  The RepeatBehavior tells the animation to keep going.

So, calling PleaseWait(true) will show the screen and start the animation.  Calling PleaseWait(false) will hide the screen (by setting the Height and Width back to 1) and stop the animation.  Having one call to start the "Please Wait" and a separate call to stop the "Please Wait" allows us to call the "show" part just before firing off an async call and then call the "hide" part in the callback after the async is complete.  This leads to some problems.

What if the async call does not return?  Maybe the database or webservice hangs for some reason.  If this happens, then the "Please Wait" screen will never go away, and the user has no choice but to close the application and try again.

Also, we have to be extremely careful in coding the callbacks.  We must make sure that we always call "hide".  This can make error handling a bit tricky.  If we forget to call "hide" for some reason, then the application is stuck and the user must restart it.

As a side note: if you're curious how the sample application works, when we click the button, it calls PleaseWait(true) and then starts a timer that is set to the number of seconds in the text box.  When the timer fires, it calls PleaseWait(false).  Again, in the real world, there would be some sort of asynchronous call in here rather than a timer.  This is just so that we can see the screen in operation.

Pros:
This is a very simple implementation.  There is not much code required for it.  Also, it works with any screen that we have (since it covers the entire application).  For the simple selection and mapping application where this screen was used, it worked fine.  The only screen it is used on is an output/reporting screen, so there is no danger of data loss if the application does hang up for some reason.

Cons:
The code is very unsafe.  If the "hide" call is never made, then the application is stuck; there is no way to get rid of the screen.  You can simulate this by setting the duration to a really long time in the sample implementation.

Verdict:
I would not recommend re-using this code in its current state.  The issues are just too big.  A more useful implementation would be to disable just the controls that we are concerned about.  For example, if we do not want someone to click a "Submit" button more than once, we should disable that control.  If we do not want someone to navigate to another screen, then we should disable the menu.  If we were to use the MVVM (Model-View-ViewModel) pattern, then we could come up with some creative ways of handling the disabling/enabling through databinding.  (As noted last time, we'll be talking a bit about MVVM in Part 5).

If we still need the "Please Wait" message, we can come up with a more robust solution by setting up an event with a callback.  This would allow us to hook the "hide" into the callback of the asynchronous call.  By doing this, we can be more confident that the "hide" method will get fired appropriately.

Next Time
This time, we saw an implementation of a Please Wait screen that allows us to make asynchronous calls behave like synchronous calls.  As noted, I would not use this implementation again; there are just too many ways for it to go wrong.

You've probably noticed by now that the sample application does not use the MVVM pattern.  Next time, we'll talk about why we might want to use MVVM and (specifically) why it was not used for this particular application.  We'll also summarize what we've seen and this will hopefully let us take the good with our next application, improve the bad, and just get rid of the ugly.

Happy Coding!

Thursday, April 12, 2012

XAML App Review - Part 3: Popup Message

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.

Popup Message
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):

On this screen, we can enter whatever message we want and then click "Show Popup".  This displays a message in the upper-right corner of the application:


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.

Pros:
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.)

Cons:
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.

Verdict:
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
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".

Happy Coding!

Wednesday, April 11, 2012

XAML App Review - Part 2: Form Manager

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 overall operation and look and feel of the application UI.  This time, we'll look at the form manager -- how the different forms/pages are swapped in and out of the client area.  As a reminder, you can download the code or run the application here: Jeremy Bytes - Downloads.

ICloseQueryable Interface
There are a couple of features in WinForms that don't exist in the Silverlight world.  In the WinForms world, a form has a "Closing" event.  You can handle this event and issue a "Cancel" that will keep the form from closing.  If the user has unsaved data on the form, this gives you a chance to ask if the user wants to save or cancel changes before exiting.

The Silverlight world does not have a "Closing" event.  One reason is that in Silverlight we are primarily working with UserControls as opposed to forms.  For all intents and purposes, these can behave exactly as if they are forms, but there are a few differences.  One of these differences is the events that are available.

In the production application, each screen has an explicit save function (meaning data is not auto-saved). In order to make sure that the user had a chance to save before leaving a screen, I created an interface (ICloseQueryable) that is implemented on each screen where data can be modified.  Here's the interface (from the ICloseQueryable.cs file in the Common folder):

This is a very simple interface with just one method.  The name of the interface comes from the Delphi world (which our team used before we moved to .NET).

Here is a page that implements the interface ("Page 1"):


And the implementation (note: comments have been removed here for brevity):

Since this screen does not have an actual data object, the CanClose method is simply checking to see if the text in the text box has been changed from the default value.  If it has been changed, then the user is given a confirmation message box.  If the method returns "true", then the page is closed; otherwise, it stays open (we'll see this in just a bit).

In the real world, the CanClose method would check something from the business layer (such as a dirty flag) to see if there are unsaved changes.

Pros:
The simple interface can be implemented in every form that needs to check for unsaved data before closing. Also, even though this wasn't the original intent, this could be used like a "Closing" event where we can do clean-up or finalization on the screen.

Cons:
There is no guarantee that the CanClose method will be called.  This particular application has a design that ensures that this method gets called before a new screen is opened.  Also, as we'll see when we look at the form manager, the CanClose method does not get called when the application itself is shut down.  But this is also a problem with Silverlight in general because it runs in a browser, and there isn't a built-in mechanism to stop a user from closing the window.

Verdict:
This functionality may be better implemented as an event in a base form (UserControl) that all of the other forms descend from.  With an event, we would have better control over when it gets fired and ensuring that it gets fired.  I made a personal decision with this one.  I have been burned by UI frameworks that force the use of a base form in order for the application to work properly.  My native reaction is to take the simpler approach first and move toward the more complex one if necessary.  For this particular application, the interface solution is adequate.  For a more complex application, I would probably consider using a base form and events.

Another thing to consider: if we instead implemented an auto-save function for the data, then there is no need for the CanClose method or the interface.  Whether we implement auto-save is very dependent on the requirements of the application.

Form Management
There are a couple of different pieces to the form management in this application.  First, let's see the forms that we'll be working with:

The MainPage.xaml is the page that opens when the application starts.  It houses the menu and has a client area that is used for docking the sub-forms.  The CloseQuery1Page.xaml and CloseQuery2Page.xaml correspond with the "Page 1" and "Page 2" menu items.  The LoginPage.xaml is docked at start up (as we'll see in just a bit), and the other pages correspond with their menu items.

Let's start by taking a look at the form controller (this is in the FormController.cs file in the Common folder):


The idea behind the FormController class is that it maintains a list of forms that have been instantiated by the application.  If the application asks for a form (by calling GetForm), the form controller will check it's collection to see if that form already exists.  If it does exist, it will return that instance.  If it does not exist, then it will create an instance of the form, add it to its internal list, and then return that instance.

Notice that GetForm takes a parameter of type "Type".  This means that we will need to get the types somehow.  I do a bit of a cheat here: I set the Tag properties of each of the menu items (which are hyperlink buttons) to the corresponding type of the form.  This is done during the MainPage load process:

I'm not a big fan of using the Tag property for this type of thing, but it does get the job done.  As we'll see in just a bit, each of the hyperlink buttons is hooked up to a single event handler.  The Tag is used to instantiate the correct form.

As a side note, the "System.Windows.Browser.HtmlPage.Plugin.Focus" method makes sure that the Silverlight plugin has the focus (as opposed to the browser address bar or other item).

So, this event handler sets the tags of the menu items and then calls the ShowControl method with the LoginPage as a parameter.  The LoginPage constructor takes the type of another page.  When login is successful, this is the next page to navigate to (you can think of this as a "ReturnUrl" that you see when using ASP.NET forms authentication).  Here's what ShowControl looks like:


ShowControl takes a UIElement parameter (the same type used by the FormController).  This checks the ClientArea of the MainPage to see if it has at least one child.  If so, then it will remove that child and add a new child -- the UIElement that was passed in.

This code makes the assumption that there is only a single child of the ClientArea at any one time.  This is fine for this application, but the code should be made "safer" before reusing this.  This could be done by looping through all of the children and removing each one before adding a new child.

Finally, if the UIElement is the LoginPage, then it will set the focus to the text box for the login id.  This, in conjunction with the call to the Plugin.Focus above, ensures that the text box has the focus when the application starts.

The last piece of the puzzle is the click event for the hyperlink buttons.  As noted above, all of the buttons share the same event handler:


Here's how this works.  First, it gets the Tag from the hyperlink button that was clicked and stores it in the newType variable.  Next, it checks the current child of the ClientArea control to see if it implements ICloseQueryable.  If so, then this gets assigned to the oldForm variable.

_currentPage is a class-level variable that holds the type of the currently docked form.  If it is the same as the form that is requested (newType), then it exits.  This makes sure we don't do work to swap out forms when we are already on the requested form.

Next, it verifies that newType is populated (just in case the Tag property was not set properly).  Then it checks IsAuthenticated (a property that tells whether the user is authenticated).  If the user is not authenticated, then it redirects to the LoginPage and passes the requested page as the next page.

Next, it checks if the oldForm variable is populated -- this will only be populated if the previous form implements the ICloseQueryable interface.  It then calls the CanClose method.  If that method returns false (the user canceled the form close), then the application stays on the current form.

If none of the previous checks force a "return", then ShowControl is called.  Notice that the parameter for the method uses the FormController.GetForm method.  This will make sure that an existing instance is used if possible.  Finally, the _currentPage variable is set to the current form.

That's how it works; now let's do a bit of analysis.

Pros:
It's fairly simple, and it works.  (I think "it works" is in the Pros column of pretty much any analysis).  One of the things that I like about this is that any UIElement can be used.  In our case, all of the forms are UserControls, but we could choose a different UIElement if it made sense.  Next, I like that we do not have to descend from a custom base class.  If the form does not implement "ICloseQueryable", then the code still works just fine.  If it does implement the interface, then we get the added functionality.

An advantage of the form controller is that we only instantiate one instance of each form.  This keeps the application from constantly creating and destroying the UserControl objects.

Cons:
As noted above, we make assumptions about the number of children in the ClientArea.  Since ClientArea is a stack panel, it could have any number of children.  This assumption could cause potential problems.  I am never comfortable with the use of the Tag property.  It solves an issue for us since it allows all of the hyperlink buttons to easily share a single event handler, but it still doesn't "smell" right.  Finally, this methodology requires that all of the forms be statically compiled.  This is generally not an issue, but if we needed to dynamically add functionality (with new forms), we would need to rework this.

A disadvantage of the form controller is that we only have one instance of each form.  If we wanted to have multiple instances of a particular form (for example, multiple Orders open at the same time), then we would need to rework the form controller.  Also, if we re-open a form, it returns to its previous state.  This may or may not be what we want.  If we wanted to discard data, then we would need to reset the form somehow.

Verdict:
For this application, the solution is appropriate.  I would make some minor changes -- specifically, some of the names could be better.  "ICloseQueryable" and "FormController" could be renamed to something more appropriate; the same is true of a number of the variables.  "Form" is used in quite a few places, but "page" or "user control" may be better in the context.

Before using this in other applications, we would need to look at the requirements.  If we need to load forms dynamically, then we would need to rework this quite a bit.  Another option would be to look at the "Silverlight Navigation Application" template in Visual Studio.  We may even be able to use MEF (the Managed Extensibility Framework) depending on the situation.  There are tons of options out there.

Next Time
We took a look at a few more places where we can improve this application.  Fortunately, we haven't really run into a "that was a complete mistake" situation, but we may come across that as we continue our review.

Next time, we'll look at a Popup Message implementation.  This allows us to show messages to users that do not require user interaction.  This is a really cool feature that has quite a bit of room for enhancement.

Happy Coding!

Tuesday, April 10, 2012

XAML App Review - Part 1: Overview

This is a continuation of the XAML App Review started with the Introduction. The articles in this series are collected together here: Jeremy Bytes - Downloads.

To get started with our XAML Application Review, let's take an overall look at the UI look and feel.  As a reminder, the XAML Tips application that we'll be looking at is a replica of a Silverlight application that went into production in 2009.  You can download the code here: Jeremy Bytes - Downloads.

Operation
First, let's take a look at how the application operates.  Here is the login screen:


Here, we can see the use of gradients that we saw in a previous article (XAML Tip: Gradients).  We'll consider the look and feel in just a moment.  On this screen, we have a menu bar to the left of the application that is used to navigate between screens.  If we click the "Popup Message" link on the left, it will take us to the following screen (Note: for this sample, authorization code has been removed, so the login screen doesn't do any validation):


The effect is that the main client area (everything but the menu bar) is replaced with a new screen.  The data screens from the original application are not re-created here, but they are collections of primarily list boxes and buttons that allow the user to make selections of existing data and to add mappings for data between systems.  We are taking a look at the overall UI design here.

Pros:
This behaves similarly to the WinForms applications that we had deployed at our site.  This gave users a familiar interface.  The application itself has a limited number of screens (there were a total of 7 screens); and most of these screens had similar operation (either data selection or data mapping).  So, we were able to give the users the advantage of a web deployment and a familiar interface.

Cons:
This behaves similarly to the WinForms application that we had deployed at our site.  (Yes, I realize that I just put this into the "Pros" section.)  Silverlight (and XAML in general) gives us amazing flexibility for UI design.  Billy Hollis (one of the "voices of reason" in the developer community) sees XAML as the opportunity for us to completely rethink how users interact with our applications.  He has said that one of the worst things you can do when coming to XAML is to simply re-host your WinForms apps.  There are tons of exciting things that we can do with XAML that would be extremely difficult in WinForms.  We should be thinking about how we can best present our applications to the users to enhance usability.

Verdict:
There's really nothing "wrong" with the overall operational design.  It fulfilled its purpose even if it's not very exciting.  I'm very big on using the right tool for the job.  This one worked well.  For other jobs, I might be looking at the page-based navigation that's available in Silverlight.  Or I might come up with something completely different -- but considering that I generally like to use well-tested solutions, I'll probably look for ideas from other developers.

Look and Feel
This application is a bit "gradient happy".  The actual data pages (which aren't shown) are mostly non-gradient list boxes and standard buttons.  Gradients aren't really "in" anymore.  But that's part of the great thing about XAML.  This application makes extensive use of styles (web developers can think of this as similar to CSS).  Because these styles are shared, they are very easy to update if we get tired of the look.

Let's take a look at how these are implemented.  Here's a snippet from the App.xaml page in the code:


These brushes are all in the application's resources collection, so they can be referenced across all of the pages in the application.  Notice the names that are used for the keys.  The names are things like "ClientBackgroundBrush" and "DarkBackgroundBrush" that tell how the brushes are used.  They do not have names like "BlueGradientBrush" or "YellowGradientBrush".  A name like "BlueGradientBrush" really limits how this can be changed.  If you change the color, then the name is no longer correct.  If you change it from a gradient brush to a solid brush, then the name is no longer correct.  Instead, if we use names that reflect how the brushes are used, we can make those color and style changes without invalidating the names.

Here is an example of some styles from the App.xaml:


This shows the styles that are used to display data to the user.  Since these values are centralized, we can easily make changes to the fonts or margins, and all of our detail controls will be affected.

Pros:
Centralizing the colors and fonts in the application resources allows us to easily update the visual elements of our application.  If we decide that we no longer like the gradients, we can change to solid brushes with different colors or patterns in this one place, and our entire application will pick up those changes.  The same is true for the fonts and alignment of our controls.

Cons:
Some of the names could be a bit better; "DarkBackgroundBrush" and "LightForegroundBrush" are a little limiting (if we wanted to switch to a light background and dark foreground).  Also, there are some styles that are in the resources section of MainPage.xaml.  And while these styles are only used on the MainPage, they should probably be centralized for consistency.

Verdict:
The colors and gradients are looking rather dated, especially compared to the Metro interfaces that are starting to become popular.  However, since the brushes and styles are centralized, it is fairly easy to update the application when we come up with a new design.  In the future, I would use fewer gradients (even though I personally like them), and I would be more consistent with the centralization of the style and brush resources.

Next Time
So far, we've seen that there are some improvements that can be made to this application.  By reviewing what we've done in the past in the context of our current experience, we can make sure that we're always moving forward.

There's still quite a bit to look at in this application.  Next time we'll be taking a look at the form manager that keeps track of the different forms and how they get docked to the client area.

Happy Coding!

Monday, April 9, 2012

XAML App Review - Introduction

The articles in this series are collected together here: Jeremy Bytes - Downloads.

As developers, we usually don't get things exactly right the first time (gasp!).  As we move from project to project, we are always learning.  To help make those learnings stick, it's useful to go back to old projects for review.  When we review an old project, we can take a new look at how we implemented certain functionality, what worked well, what could use some improvement, and what things we would never do again.

With that in mind, I'll be taking a look at an application that I built several years ago.  This was a business application in Silverlight.  The primary development work was done in Silverlight 2; Silverlight 3 came out right as I was in the final development stages.  I've replicated the UI in the XAML Tips application that I used a few articles ago: XAML Tip - Gradient.

You can see the replica application in action here: XAML Tips Sample Application.  The code will be made available as we look at some of the specifics.

New Technologies
This was the first Silverlight application that I put into production.  As such, it came out as a hybrid between a web application and a WinForms application.  The primary goal of the application was to check the feasibility of using Silverlight in our environment.  The business logic of the application was well defined (and rather simple).  This made it a good candidate to try some unfamiliar technologies: Silverlight and CSLA for Silverlight.

CSLA is a business object framework that I used for many years with great success.  I won't be talking about CSLA here, but you can get tons of good information at http://www.lhotka.net (or just start a web search for CSLA).  CSLA for Silverlight is a bit different from the full .NET version I had been working with -- things like asynchronous web service calls and no direct data access on the client (this was the world before RIA Services, too).  CSLA for Silverlight worked out very well for this project, and I highly recommend it for the right types of projects.

The Good, the Bad, and the Ugly
Since this was my first real-world application with Silverlight, it wasn't perfect.  There were some things that worked very well, and I have used again and again.  There are some things that worked well for this particular application but need some improvement to make them work better with other applications.  And there are some things that are nothing but kludges.

In looking at the different features of the UI (we won't be looking at the business layer for this review), we'll look at the pros and cons of the implementation of each UI feature.  And hopefully, we'll see how we can improve on them.

Features:
  • Form Manager - responsible for managing the different forms/pages of the application that get loaded into the client area.
  • Close Query Interface - works with the Forms Manager to give the current form a chance to prevent itself from closing (for example, if there is unsaved data).
  • Pop-up Message - gives the user status messages from the application in way that does not require a user action.
  • Please Wait Screen - stops the user from interacting with the application while certain types of functions are running.
Get Ready
So, get ready to see some creative techniques to different problems.  And if you have anything to add to my review, be sure to send them along in the comments.

Until then, feel free to take a look at the application: XAML Tips Sample Application.

Happy Coding!