Code Camp is all about developers sharing with developers. Now is your chance. The next So Cal Code Camp is 2 months away (June 23rd and 24th).
Code Camp is made possible by developers volunteering to speak for other developers. We've all learned interesting things; now is your chance to pick your favorite and share it with others. Every developer should try speaking at least once. Code Camp is a great place to get started because we're talking to folks just like us.
For some tips on preparing your session, check out this article: Meet the Next Code Camp Speaker: You!
You've got a little over 8 weeks to put your presentation together. So pick a topic and sign up at the So Cal Code Camp site.
Happy Speaking!
Wednesday, April 25, 2012
Tuesday, April 24, 2012
Upcoming Speaking Engagements
I'll be speaking in a few different areas over the next several weeks. Be sure to stop by if you're in the area. Heading to your local user group is a great way to meet other developers, share experiences, and learn something new.
Las Vegas, NV
Thursday, April 26th @ 7:00 p.m.
dotNet Group.org
Topic: Learn to Love Lambdas
Lambda expressions can be confusing the first time you walk up to them. But once you get to know them, you’ll see that they are a great addition to your toolbox. Used properly, they can add elegance and simplicity to your code. And some .NET constructs (such as LINQ) lend themselves to lambda expressions.
San Diego, CA
Tuesday, May 1st @ 6:00 p.m.
San Diego .NET Developers Group
Topic: Learn the Lingo: Design Patterns
You already use Design Patterns but probably don't know it. Observer, Adapter, Iterator, Proxy -- Learning the lingo allows you to better communicate your ideas with other developers. We'll take a look at several GoF patterns that we regularly use without realizing it. Don't know who the GoF is? Join us to find out.
San Bernardino, CA
Tuesday, May 8th @ 6:30 p.m.
Inland Empire .NET User's Group
Topic: IEnumerable, ISaveable, IDontGetIt: Understanding .NET Interfaces
Best practices tell us to program to an abstraction rather than a concrete class. Let's start by understanding what a .NET Interface is and what it means to our code. After that, we'll look at a couple of practical implementations that can make our code more robust and extensible.
Happy Coding!
Las Vegas, NV
Thursday, April 26th @ 7:00 p.m.
dotNet Group.org
Topic: Learn to Love Lambdas
Lambda expressions can be confusing the first time you walk up to them. But once you get to know them, you’ll see that they are a great addition to your toolbox. Used properly, they can add elegance and simplicity to your code. And some .NET constructs (such as LINQ) lend themselves to lambda expressions.
San Diego, CA
Tuesday, May 1st @ 6:00 p.m.
San Diego .NET Developers Group
Topic: Learn the Lingo: Design Patterns
You already use Design Patterns but probably don't know it. Observer, Adapter, Iterator, Proxy -- Learning the lingo allows you to better communicate your ideas with other developers. We'll take a look at several GoF patterns that we regularly use without realizing it. Don't know who the GoF is? Join us to find out.
San Bernardino, CA
Tuesday, May 8th @ 6:30 p.m.
Inland Empire .NET User's Group
Topic: IEnumerable, ISaveable, IDontGetIt: Understanding .NET Interfaces
Best practices tell us to program to an abstraction rather than a concrete class. Let's start by understanding what a .NET Interface is and what it means to our code. After that, we'll look at a couple of practical implementations that can make our code more robust and extensible.
Happy Coding!
Sunday, April 22, 2012
Overview of the MVVM Design Pattern
The Model-View-ViewModel (MVVM) design pattern gets a lot of attention (as well it should). The pattern itself is fairly straight-forward. Where many developers get stuck (especially developers just walking up to the XAML world) is with the implementation. Often developers walk up to a framework/toolkit that offers help with implementation of the MVVM pattern, and they get mired in the intricacies of the particular framework without understanding the pattern itself.
The frameworks are important. They offer libraries that make the implementation of the pattern cleaner by encapsulating functionality that is not offered in the underlying XAML engine. What is more important is that we have a good understanding of the pattern itself before diving in to one of these frameworks. If we understand the "why" of the pattern, then we are less likely to make pattern-breaking errors when we get to the "how" of the implementation.
In a previous article (XAML App Review - Part 5: MVVM and Wrap Up), we took a very quick look at MVVM. Today, we'll dive deeper into the pattern itself: a little bit of history, the problem spaces that it is designed to resolve, the various parts that make up the pattern, and some consequences of using the pattern. In a future article, we'll look at a sample implementation of the pattern in a XAML-based application.
A Little Bit of History
The MVVM pattern is based on the concepts of previous Presentation design patterns including MVC (Model-View-Controller) and MVP (Model-View-Presenter). The MVC pattern was developed before the RAD tools that we use today, when the developer had to build the UI elements from scratch (or bring them in from a shared library). Andrew Hunt and David Thomas describe the key concept of MVC as "separating the model from both the GUI that represents it and the controls that manage the view" [Andrew Hunt and David Thomas, The Pragmatic Programmer, Addison-Wesley, 1999].
These patterns have moved forward into our modern tools (as with ASP.NET MVC). As we can tell from the names, these patterns share common ideas: the Model and the View. We will discuss each of these in more detail below.
The MVVM pattern is a variation on the MVC and MVP patterns based on the presentation model of XAML. XAML offers a very rich binding mechanism, and the MVVM pattern uses this binding mechanism as the "goo" that holds everything together.
A Bit of Review
Christopher Alexander gives us a definition of design patterns that we use today:
For more information on Design Patterns in general, please refer to Learn the Lingo: Design Patterns.
For simplicity, we'll stick to the four basic parts of a design pattern: Pattern Name, Problem Space, Solution, and Consequences. We've already seen the Pattern Name: Model-View-ViewModel. We'll see how this describes the different components as we get to the Solution. Normally, we would describe the Problem Space before the Solution, but because of the nature of the pattern, it will be easiest for us to look at the Solution first.
MVVM: Solution
As the pattern name implies, the MVVM pattern consists of three primary components. Note: I'm using the word "component" here in the generic sense ("parts" or "pieces"). After taking a look at each of the components, we will see how they interact with each other.
Model
The Model encapsulates the business logic and data that is used by the application. The best way to think of the Model is everything that is not Presentation -- when using a layered application approach, it is everything below the presentation layer (which may include a business layer, service layer, data access layer, data storage layer, etc.). In most scenarios, our Model will be abstracted into various components. For example, we may have a repository that is responsible for retrieving and persisting objects through a service, and the service is responsible for interacting with the data store (such as a database). And what types of data objects are exposed will vary; they may be smart objects (if we are doing Object Oriented Programming) or data entities (if we are doing Entity or Domain-Based Development).
The actual implementation of the Model is not important to the overall MVVM pattern, although the implementation of the objects in the Model may affect how the objects are exposed in the ViewModel. The Model should not have any presentation logic.
ViewModel
The ViewModel encapsulates the presentation logic and the data that is used by the View. We can think of this as the "goo" that holds things together. MVVM is designed around the powerful data binding engine that is available in XAML. The ViewModel is responsible for taking the data objects that are available in the Model and making them available as properties to which the View can data bind.
But the ViewModel is responsible for more than just exposing Model objects as properties. It also provides properties that are used for the presentation logic of the application. For example, lets say that we have an Order object, and whether it is read-only will depend on whether the order has already shipped. The Model would handle determining the read-only state of the object (since this is part of the business logic), but then the ViewModel could expose an OrderReadOnly property that the View can use. The View can then bind the IsReadOnly property for a particular control (or set of controls) to the OrderReadOnly property of the ViewModel.
The ViewModel also handles any interaction between the View and the Model. This is accomplished by exposing methods or commands that the View can call. The ViewModel then uses those methods to make calls into the Model. We'll take a look at this more closely in the Interactions section below.
View
The View is what the user sees on the screen -- all of the UI elements. This is the collection of XAML elements that make up the user interface (user controls, buttons, labels, text boxes) as well as the supporting items that assist these elements (styles, animations, control templates).
As we've seen, MVVM is based on XAML data binding. This means that our view is usually chock-full of data bound attributes. As noted in the ViewModel description above, this is not limited to data, but also other properties that affect interaction. For example, we may have a TextBox that has its Text property is data bound to a property in the ViewModel (such as OrderDate). But that same TextBox may also have its IsReadOnly or IsEnabled property data bound to properties in the ViewModel. We can even have visual properties like FontSize or Foreground determined by data binding to ViewModel properties (along with appropriate value converters).
Separation of Concerns and Interaction
Now that we've seen the components and what they are responsible for, let's take a look at how they interact with each other.
The View only knows about ViewModel. The View does not have any direct knowledge of the Model. It only knows about the ViewModel. The View is generally responsible for creating the ViewModel, and this is almost always a one-to-one relationship. In an ideal world, the View would not have any code-behind (but some people are more adamant about this than others -- it depends on the implementation).
The ViewModel knows about the Model. The ViewModel is responsible for retrieving any objects that it needs to expose from the Model. This can be a one-to-one or one-to-many relationship. An example of a one-to-one relationship may be a ViewModel that exposes a Customer object from the model; an example of a one-to-many relationship may be a ViewModel that needs to expose an Order that contains a Customer along with multiple Products. How these are exposed (as single or composite objects) is dependent on the needs of the application. The ViewModel should depend on the Model for business logic (for example, calling to the Model to determine whether an object is editable based on the object's data values).
The ViewModel does not have direct knowledge of the View -- meaning, the ViewModel should not reference any of the controls or UI elements that are part of the View. It can contain Presentation Logic (for example, exposing and setting properties that determine whether controls are shown or hidden), but it should leave it up to the View to determine how the elements are actually presented.
The Model does not have direct knowledge of the ViewModel or the View. It is up to the ViewModel to handle any interaction with the Model (never the other way around). The Model should contain the Business Logic, but the Presentation Logic should be limited to the ViewModel.
Example: Property Interaction
Let's take a look at a specific business rule that affects our user interface and see which components have the responsibility along the way. To go back to our Order example, let's say that the Order cannot be changed after it has shipped. The Model would contain the business logic to determine whether the Order has been shipped (perhaps by checking a ShippingDate field) and then set a ReadOnly property on the Order object appropriately. The ViewModel would take this ReadOnly property and expose it to the View. The View could then determine how to use this property through data binding. For example, the View may have the IsReadOnly property on a set of TextBoxes data bound to the ViewModel property, or it may completely change the visual elements by showing TextBlocks if the ReadOnly property on the ViewModel is set to true. The important part to remember is that the Model is responsible for the business logic (determining whether the Order is changeable), the ViewModel is responsible for exposing this property to the View, and the View is responsible for using the property to control the actual UI elements.
Example: Method Interaction
Now, a different perspective: let's say we have a Save button in our View, and we need to save the current object on the screen. Note: there are several ways of implementing this; this just shows one way. In our View, we have a Button with its Command property data bound to a SaveOrderCommand in the ViewModel. In the ViewModel, the SaveOrderCommand object executes, which calls the Repository<Order>.Save() method (in the Model) and passes in the current Order object. In the Model, the Save method in the repository performs the appropriate action, such as saving the Order to the database. Note the interaction: the View only calls into the ViewModel, and it is up to the ViewModel to call into the Model. Then the Model does the actual work.
MVVM: Problem Space
Now that we've seen the various components of the MVVM pattern, let's take a look at why we would want to use the pattern. At its core, the pattern addresses three main problem spaces:
Problem Space: Mixture of Presentation and Business Logic
Application developers often mix Presentation Logic code and Business Logic code together. It's just too easy to do this with our modern tools: just open a new WPF project in Visual Studio, drag-and-drop some controls on to the XAML workspace, flip over to the code-behind and start slapping code together. But coding this way leads to a maintenance nightmare.
Solution: MVVM encourages good separation of Presentation and Business Logic. With clearly defined components, the developer has appropriate places to put the presentation logic (the ViewModel) separate from the business logic (the Model).
A small caveat: notice that I used the word "encourages". There is nothing in the pattern (or any pattern) that forces you to put code in one place or another. Once we start to put code in the wrong area, we end up breaking the pattern, but our code might still work. We need to be attentive that we are actually putting the code in the appropriate area. If we start to break the pattern, then we will lose the benefits.
Problem Space: Unit Testing of the Presentation Layer is Difficult
When we are unit testing (which should be always), our goal is to have tests that cover as much of our code as possible -- this includes the Presentation functionality. When developing unit tests against a traditional UI (event handlers in the code-behind), it is difficult to split out individual functionality. For example, if we want to unit test a Button's click event, we can create a unit test around the event handler itself. But in the set up for the test, we will need to instantiate a Button object (the "sender" parameter) by using a fake or a mock. This may also mean that we need to instantiate an entire UserControl object as a parent for the Button in order to get a valid test.
Solution: The ViewModel in MVVM lends itself to cleaner unit testing. Using the example above, let's say that instead of the Button click event performing an action directly, it calls a method in the ViewModel. Now, we can easily unit test the method in the ViewModel. Since the ViewModel does not have reference to UI elements, we would not need to instantiate them for the unit test. This leads to code that is easier to test and is easier to isolate. Note: method calls will generally travel from the ViewModel to the Model, but because we have these "seams" in our application, it is easier to fake or mock those interactions in our unit tests.
Problem Space: File Sharing Between Designers and Developers
In situations where there are dedicated interaction designers and application developers, it can be difficult to coordinate work since the designers and developers need to interact with the same set of source files (for example, the MainPage.xaml and MainPage.xaml.cs files that travel together in source control). This can get especially tricky when both areas need to check in changes to the same files at the same time. In addition, the interaction designers need a certain amount of knowledge of the development environment so that they do not inadvertently break the developer's code.
Solution: With the physical separation of the View and ViewModel in MVVM, designers and developers can work more independently and safely. The designers are only working with the View (XAML), and the developers are only working with the ViewModel and Model which are separate code files (.cs or .vb). If the code-behind the XAML is eliminated (or at least minimized), then there is less risk that a designer could accidentally break some developer code.
This does not mean that the designers and developers work in isolation. They still need constant communication. What the designer can do with the UI is dependent upon the properties and methods that are exposed by the developers. Collaboration is still vitally important, but MVVM will minimize the likelihood that they will need to edit the same source files at the same time.
One small caveat: in many of the development shops that we work in, there is no separate designer; we are both the designer and developer. But even if we are not able to take advantage of this particular solution, we can still get the advantages of the clear separation of concerns and ability to unit test the presentation layer.
MVVM: Consequences
Every Design Pattern has both benefits and costs. The MVVM pattern is no different.
Consequence: Added Complexity
MVVM adds complexity to the Presentation Layer of the application. This is an additional learning curve for the development team.
When given a choice between dumbing-down code or smartening-up developers, I will choose the latter. I always prefer to bring up the skill set of the development team. But there may be some scenarios where this is not possible due to time constraints (ever heard this one before?). We need to make sure that the developers on the team understand the pattern before we start using it extensively; otherwise, we may find folks who take short cuts to get things to work and end up breaking the pattern.
Consequence: Errors Move from Compile Time to Run Time
As we've seen, implementation of MVVM is made possible through the very flexible data binding that is available in the XAML world. One of the downsides is that incorrect data binding will not generate errors at compile time. These errors are moved to run time, and often the errors produce silent failures (simply an empty TextBox or other unexpected behavior). Unfortunately, unit testing will most likely not catch these errors either since we are testing our ViewModel and not the View (where the bindings are specified).
These can be difficult to debug. The best tip that I have is to make sure you have the Output window open in Visual Studio when debugging your application. If there is a failed data binding, it will show up in the Output window.
Weighing the Costs
What is important is that we understand the costs and determine that we are willing to accept those costs in order to receive the benefits. If we are aware of the negative consequences of the pattern, then we can take steps to mitigate them. Just like every other tool in the toolbox, we need to make sure that we are picking the right one for the job. If we are not getting the benefits of the pattern, then we are only getting the costs, and we should reconsider our approach.
What About Implementation?
We'll need to save implementation for another day. As we noted earlier, there are a number of frameworks that can assist us.
Microsoft Patterns & Practices offers Prism as guidance for creating XAML-based (WPF, Silverlight, Windows Phone) applications. This includes using MVVM for the presentation layer. Prism provides a number of classes and interfaces that help make the implementation of MVVM cleaner and more generic. This results in less boiler-plate and replicated code in the application. Of course, it is always possible to implement these abstractions and helpers yourself, but someone else has already done the hard work. There is also great documentation available, including Implementing the MVVM Pattern.
Another popular option is the MVVM Lite Toolkit. This toolkit puts an emphasis on what they call "blendability" -- the ability to open and edit the user interface in Expression Blend.
Paul Sheriff shows the MVVM pattern in action without using external frameworks: The Basics of MVVM. This has advantages of focusing on the pattern rather than the framework (as was mentioned earlier). But there are some things that are a bit harder to do. I've done some implementations using a similar method, and there are pros and cons as with everything else.
And there are plenty of other implementations as well. If we go back to our Christopher Alexander quote above, patterns describe a solution "in such a way that you can use this solution a million times over, without ever doing it the same way twice." This doesn't mean that we should re-invent the wheel; it just means that there are different types of wheels to choose from.
Wrap Up
MVVM is a very important pattern in the XAML world. Much of the samples and guidance revolving around the latest implementations (Windows Phone 7 and Windows 8) use MVVM as the core presentation pattern. What is important is that we understand the pattern itself, the components that make up the solution, and why we are using the pattern. Once we have these things down, we can make better decisions when we are implementing MVVM in our own applications. And when we are using an MVVM framework, we have a strong foundation to ensure that we are using the framework appropriately and that we are adhering to the principles of the pattern itself.
I am currently working on an application that shows a simple implementation of MVVM. That code will be available in the near future.
Happy Coding!
The frameworks are important. They offer libraries that make the implementation of the pattern cleaner by encapsulating functionality that is not offered in the underlying XAML engine. What is more important is that we have a good understanding of the pattern itself before diving in to one of these frameworks. If we understand the "why" of the pattern, then we are less likely to make pattern-breaking errors when we get to the "how" of the implementation.
In a previous article (XAML App Review - Part 5: MVVM and Wrap Up), we took a very quick look at MVVM. Today, we'll dive deeper into the pattern itself: a little bit of history, the problem spaces that it is designed to resolve, the various parts that make up the pattern, and some consequences of using the pattern. In a future article, we'll look at a sample implementation of the pattern in a XAML-based application.
A Little Bit of History
The MVVM pattern is based on the concepts of previous Presentation design patterns including MVC (Model-View-Controller) and MVP (Model-View-Presenter). The MVC pattern was developed before the RAD tools that we use today, when the developer had to build the UI elements from scratch (or bring them in from a shared library). Andrew Hunt and David Thomas describe the key concept of MVC as "separating the model from both the GUI that represents it and the controls that manage the view" [Andrew Hunt and David Thomas, The Pragmatic Programmer, Addison-Wesley, 1999].
These patterns have moved forward into our modern tools (as with ASP.NET MVC). As we can tell from the names, these patterns share common ideas: the Model and the View. We will discuss each of these in more detail below.
The MVVM pattern is a variation on the MVC and MVP patterns based on the presentation model of XAML. XAML offers a very rich binding mechanism, and the MVVM pattern uses this binding mechanism as the "goo" that holds everything together.
A Bit of Review
Christopher Alexander gives us a definition of design patterns that we use today:
Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over without ever doing it the same way twice. [Alexander, et al., A Pattern Language, Oxford, 1977]One of the important parts of this definition is that a pattern describes a core of the solution. The pattern does not describe a particular implementation. There are tons of frameworks that help us with implementation: Prism, Caliburn, MVVM Lite, and many, many others. These all assist us with implementing the MVVM pattern (and as noted, we may be most successful with one of these frameworks), but no implementation is the pattern itself.
For more information on Design Patterns in general, please refer to Learn the Lingo: Design Patterns.
For simplicity, we'll stick to the four basic parts of a design pattern: Pattern Name, Problem Space, Solution, and Consequences. We've already seen the Pattern Name: Model-View-ViewModel. We'll see how this describes the different components as we get to the Solution. Normally, we would describe the Problem Space before the Solution, but because of the nature of the pattern, it will be easiest for us to look at the Solution first.
MVVM: Solution
As the pattern name implies, the MVVM pattern consists of three primary components. Note: I'm using the word "component" here in the generic sense ("parts" or "pieces"). After taking a look at each of the components, we will see how they interact with each other.
Model
The Model encapsulates the business logic and data that is used by the application. The best way to think of the Model is everything that is not Presentation -- when using a layered application approach, it is everything below the presentation layer (which may include a business layer, service layer, data access layer, data storage layer, etc.). In most scenarios, our Model will be abstracted into various components. For example, we may have a repository that is responsible for retrieving and persisting objects through a service, and the service is responsible for interacting with the data store (such as a database). And what types of data objects are exposed will vary; they may be smart objects (if we are doing Object Oriented Programming) or data entities (if we are doing Entity or Domain-Based Development).
The actual implementation of the Model is not important to the overall MVVM pattern, although the implementation of the objects in the Model may affect how the objects are exposed in the ViewModel. The Model should not have any presentation logic.
ViewModel
The ViewModel encapsulates the presentation logic and the data that is used by the View. We can think of this as the "goo" that holds things together. MVVM is designed around the powerful data binding engine that is available in XAML. The ViewModel is responsible for taking the data objects that are available in the Model and making them available as properties to which the View can data bind.
But the ViewModel is responsible for more than just exposing Model objects as properties. It also provides properties that are used for the presentation logic of the application. For example, lets say that we have an Order object, and whether it is read-only will depend on whether the order has already shipped. The Model would handle determining the read-only state of the object (since this is part of the business logic), but then the ViewModel could expose an OrderReadOnly property that the View can use. The View can then bind the IsReadOnly property for a particular control (or set of controls) to the OrderReadOnly property of the ViewModel.
The ViewModel also handles any interaction between the View and the Model. This is accomplished by exposing methods or commands that the View can call. The ViewModel then uses those methods to make calls into the Model. We'll take a look at this more closely in the Interactions section below.
View
The View is what the user sees on the screen -- all of the UI elements. This is the collection of XAML elements that make up the user interface (user controls, buttons, labels, text boxes) as well as the supporting items that assist these elements (styles, animations, control templates).
As we've seen, MVVM is based on XAML data binding. This means that our view is usually chock-full of data bound attributes. As noted in the ViewModel description above, this is not limited to data, but also other properties that affect interaction. For example, we may have a TextBox that has its Text property is data bound to a property in the ViewModel (such as OrderDate). But that same TextBox may also have its IsReadOnly or IsEnabled property data bound to properties in the ViewModel. We can even have visual properties like FontSize or Foreground determined by data binding to ViewModel properties (along with appropriate value converters).
Separation of Concerns and Interaction
Now that we've seen the components and what they are responsible for, let's take a look at how they interact with each other.
The View only knows about ViewModel. The View does not have any direct knowledge of the Model. It only knows about the ViewModel. The View is generally responsible for creating the ViewModel, and this is almost always a one-to-one relationship. In an ideal world, the View would not have any code-behind (but some people are more adamant about this than others -- it depends on the implementation).
The ViewModel knows about the Model. The ViewModel is responsible for retrieving any objects that it needs to expose from the Model. This can be a one-to-one or one-to-many relationship. An example of a one-to-one relationship may be a ViewModel that exposes a Customer object from the model; an example of a one-to-many relationship may be a ViewModel that needs to expose an Order that contains a Customer along with multiple Products. How these are exposed (as single or composite objects) is dependent on the needs of the application. The ViewModel should depend on the Model for business logic (for example, calling to the Model to determine whether an object is editable based on the object's data values).
The ViewModel does not have direct knowledge of the View -- meaning, the ViewModel should not reference any of the controls or UI elements that are part of the View. It can contain Presentation Logic (for example, exposing and setting properties that determine whether controls are shown or hidden), but it should leave it up to the View to determine how the elements are actually presented.
The Model does not have direct knowledge of the ViewModel or the View. It is up to the ViewModel to handle any interaction with the Model (never the other way around). The Model should contain the Business Logic, but the Presentation Logic should be limited to the ViewModel.
Example: Property Interaction
Let's take a look at a specific business rule that affects our user interface and see which components have the responsibility along the way. To go back to our Order example, let's say that the Order cannot be changed after it has shipped. The Model would contain the business logic to determine whether the Order has been shipped (perhaps by checking a ShippingDate field) and then set a ReadOnly property on the Order object appropriately. The ViewModel would take this ReadOnly property and expose it to the View. The View could then determine how to use this property through data binding. For example, the View may have the IsReadOnly property on a set of TextBoxes data bound to the ViewModel property, or it may completely change the visual elements by showing TextBlocks if the ReadOnly property on the ViewModel is set to true. The important part to remember is that the Model is responsible for the business logic (determining whether the Order is changeable), the ViewModel is responsible for exposing this property to the View, and the View is responsible for using the property to control the actual UI elements.
Example: Method Interaction
Now, a different perspective: let's say we have a Save button in our View, and we need to save the current object on the screen. Note: there are several ways of implementing this; this just shows one way. In our View, we have a Button with its Command property data bound to a SaveOrderCommand in the ViewModel. In the ViewModel, the SaveOrderCommand object executes, which calls the Repository<Order>.Save() method (in the Model) and passes in the current Order object. In the Model, the Save method in the repository performs the appropriate action, such as saving the Order to the database. Note the interaction: the View only calls into the ViewModel, and it is up to the ViewModel to call into the Model. Then the Model does the actual work.
MVVM: Problem Space
Now that we've seen the various components of the MVVM pattern, let's take a look at why we would want to use the pattern. At its core, the pattern addresses three main problem spaces:
Problem Space: Mixture of Presentation and Business Logic
Application developers often mix Presentation Logic code and Business Logic code together. It's just too easy to do this with our modern tools: just open a new WPF project in Visual Studio, drag-and-drop some controls on to the XAML workspace, flip over to the code-behind and start slapping code together. But coding this way leads to a maintenance nightmare.
Solution: MVVM encourages good separation of Presentation and Business Logic. With clearly defined components, the developer has appropriate places to put the presentation logic (the ViewModel) separate from the business logic (the Model).
A small caveat: notice that I used the word "encourages". There is nothing in the pattern (or any pattern) that forces you to put code in one place or another. Once we start to put code in the wrong area, we end up breaking the pattern, but our code might still work. We need to be attentive that we are actually putting the code in the appropriate area. If we start to break the pattern, then we will lose the benefits.
Problem Space: Unit Testing of the Presentation Layer is Difficult
When we are unit testing (which should be always), our goal is to have tests that cover as much of our code as possible -- this includes the Presentation functionality. When developing unit tests against a traditional UI (event handlers in the code-behind), it is difficult to split out individual functionality. For example, if we want to unit test a Button's click event, we can create a unit test around the event handler itself. But in the set up for the test, we will need to instantiate a Button object (the "sender" parameter) by using a fake or a mock. This may also mean that we need to instantiate an entire UserControl object as a parent for the Button in order to get a valid test.
Solution: The ViewModel in MVVM lends itself to cleaner unit testing. Using the example above, let's say that instead of the Button click event performing an action directly, it calls a method in the ViewModel. Now, we can easily unit test the method in the ViewModel. Since the ViewModel does not have reference to UI elements, we would not need to instantiate them for the unit test. This leads to code that is easier to test and is easier to isolate. Note: method calls will generally travel from the ViewModel to the Model, but because we have these "seams" in our application, it is easier to fake or mock those interactions in our unit tests.
Problem Space: File Sharing Between Designers and Developers
In situations where there are dedicated interaction designers and application developers, it can be difficult to coordinate work since the designers and developers need to interact with the same set of source files (for example, the MainPage.xaml and MainPage.xaml.cs files that travel together in source control). This can get especially tricky when both areas need to check in changes to the same files at the same time. In addition, the interaction designers need a certain amount of knowledge of the development environment so that they do not inadvertently break the developer's code.
Solution: With the physical separation of the View and ViewModel in MVVM, designers and developers can work more independently and safely. The designers are only working with the View (XAML), and the developers are only working with the ViewModel and Model which are separate code files (.cs or .vb). If the code-behind the XAML is eliminated (or at least minimized), then there is less risk that a designer could accidentally break some developer code.
This does not mean that the designers and developers work in isolation. They still need constant communication. What the designer can do with the UI is dependent upon the properties and methods that are exposed by the developers. Collaboration is still vitally important, but MVVM will minimize the likelihood that they will need to edit the same source files at the same time.
One small caveat: in many of the development shops that we work in, there is no separate designer; we are both the designer and developer. But even if we are not able to take advantage of this particular solution, we can still get the advantages of the clear separation of concerns and ability to unit test the presentation layer.
MVVM: Consequences
Every Design Pattern has both benefits and costs. The MVVM pattern is no different.
Consequence: Added Complexity
MVVM adds complexity to the Presentation Layer of the application. This is an additional learning curve for the development team.
When given a choice between dumbing-down code or smartening-up developers, I will choose the latter. I always prefer to bring up the skill set of the development team. But there may be some scenarios where this is not possible due to time constraints (ever heard this one before?). We need to make sure that the developers on the team understand the pattern before we start using it extensively; otherwise, we may find folks who take short cuts to get things to work and end up breaking the pattern.
Consequence: Errors Move from Compile Time to Run Time
As we've seen, implementation of MVVM is made possible through the very flexible data binding that is available in the XAML world. One of the downsides is that incorrect data binding will not generate errors at compile time. These errors are moved to run time, and often the errors produce silent failures (simply an empty TextBox or other unexpected behavior). Unfortunately, unit testing will most likely not catch these errors either since we are testing our ViewModel and not the View (where the bindings are specified).
These can be difficult to debug. The best tip that I have is to make sure you have the Output window open in Visual Studio when debugging your application. If there is a failed data binding, it will show up in the Output window.
Weighing the Costs
What is important is that we understand the costs and determine that we are willing to accept those costs in order to receive the benefits. If we are aware of the negative consequences of the pattern, then we can take steps to mitigate them. Just like every other tool in the toolbox, we need to make sure that we are picking the right one for the job. If we are not getting the benefits of the pattern, then we are only getting the costs, and we should reconsider our approach.
What About Implementation?
We'll need to save implementation for another day. As we noted earlier, there are a number of frameworks that can assist us.
Microsoft Patterns & Practices offers Prism as guidance for creating XAML-based (WPF, Silverlight, Windows Phone) applications. This includes using MVVM for the presentation layer. Prism provides a number of classes and interfaces that help make the implementation of MVVM cleaner and more generic. This results in less boiler-plate and replicated code in the application. Of course, it is always possible to implement these abstractions and helpers yourself, but someone else has already done the hard work. There is also great documentation available, including Implementing the MVVM Pattern.
Another popular option is the MVVM Lite Toolkit. This toolkit puts an emphasis on what they call "blendability" -- the ability to open and edit the user interface in Expression Blend.
Paul Sheriff shows the MVVM pattern in action without using external frameworks: The Basics of MVVM. This has advantages of focusing on the pattern rather than the framework (as was mentioned earlier). But there are some things that are a bit harder to do. I've done some implementations using a similar method, and there are pros and cons as with everything else.
And there are plenty of other implementations as well. If we go back to our Christopher Alexander quote above, patterns describe a solution "in such a way that you can use this solution a million times over, without ever doing it the same way twice." This doesn't mean that we should re-invent the wheel; it just means that there are different types of wheels to choose from.
Wrap Up
MVVM is a very important pattern in the XAML world. Much of the samples and guidance revolving around the latest implementations (Windows Phone 7 and Windows 8) use MVVM as the core presentation pattern. What is important is that we understand the pattern itself, the components that make up the solution, and why we are using the pattern. Once we have these things down, we can make better decisions when we are implementing MVVM in our own applications. And when we are using an MVVM framework, we have a strong foundation to ensure that we are using the framework appropriately and that we are adhering to the principles of the pattern itself.
I am currently working on an application that shows a simple implementation of MVVM. That code will be available in the near future.
Happy Coding!
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:
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:
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!
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).
- 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.
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!
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!
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!
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!
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:
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!
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.
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!