Using a RSS Feed to Populate Data in Expression Blend

•March 27, 2012 • Comments Off

One of the most simple and effective ways of getting design data for testing look and feel into a WPF or Silverlight project is via RSS (the other way is by defining a data source directly from within Blend). I have used this method for trying out custom control design as seen here and here. Although this technique has been covered in a couple of places on the web I would like to add my entry for this – more as a place holder for my own easy access as anything J.

Well here goes.

  1. Find an RSS feed from your own collection or anywhere else for that matter – the example does not require a specific feed address. This is because all RSS feeds follow the same XML Schema when streaming content.
  2. Open Expression Blend and create either a Silverlight or WPF project – the technique works for both types of project.

  3. In the resulting main window add a list box. Once again the type of control may vary as long as it supports an item source of some kind so data grids, combo boxes, list views, etc. will all suffice.
  4. Now take your RSS feed address and enter it as a new XML data source. Here I am going to use the RSS feed from UX Magazine (http://feeds.feedburner.com/webdesigntutsplus).

     

     

  5. Once the feed data has been parsed the following structure should appear in Blend.

  6. The most important XML element to us is the “item” element. Simply drag this element to the list box (or other element) that was placed on Blend’s design canvas. Something similar to the following screenshot should now appear:

  7. The data context now needs to be set to the LayoutRoot grid by dragging the XML element “rss” onto it as shown below.

  8. The ItemsSource of the list box can be set by dropping the XML element “items” onto the list box and selecting ItemsSource form the combo box as shown here:

    The list box has now the required details within it – even

  9. The final tasks are to style the items, items container, etc. Clicking on the list box and selecting the Edit Additional Templates -> Edit Generated Items ->Create Empty allows the basic data template to be built

  10. Editing the resultant data template

  11. Dropping the XML element “title” from the data source onto the selected data template


    results in the following design-time population:

Of course far more can be achieved on styling the list box than shown here – but that is an exercise for the reader J

That’s all Folks…

Paged Listbox Design

•March 26, 2012 • 1 Comment

Customers and users always have good and sometimes facinating ideas about how thier data should be represented on the screen. One of my recent customers did not like the way the standard list box functions finding it frustrating to search through a long list to select an item. The point being that if I move away from the list box it does not keep the focus of where I last visited in the list – a non-selected element found in the list was difficult to navigate back to based only on the scrollbar position. The proposal was to be able to page through the list box items and to be left with a possible page number if the list box had to be left and returned to later.

The code itself is rather simple – basically there is only a need for a Listbox and a DataPager as can be seen below:

            <ListBox x:Name="listBox"
                ItemsSource="{Binding FeedDetails, Mode=OneWay}" 
                ItemTemplate="{StaticResource itemTemplate}" 
                ItemContainerStyle="{StaticResource ListBoxItemStyle1}" 
                Style="{StaticResource ListBoxStyle1}" 
                ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
                ItemsPanel="{StaticResource ItemsPanelTemplate}" }" 
                />
            <sdk:DataPager PageSize="5" Source="{Binding FeedDetails, Mode=OneWay}" />

The final paged listbox with all its styling can be seen below:

That’s all Folks…

That Missing Silverlight Binding Update

•February 1, 2012 • 2 Comments

I am surely not the first in this case to notice that Silverlight does not perform in the same way as WPF in certain aspects. One of those niceties that I relied on in WPF that does not appear within Silverlight is the ability to receive an event what the contents of a Textbox have be updated. This event is central in the validation process, especially in the reactive validation. For example it is not possible in Silverlight to validate character input via the IErrorInfo process but only to validate the complete content when navigating away from the Textbox. In a great number of real-life situations the validation is directly on input allowing the UI to reactively interact with the user providing instant feedback over the status of the input.

So, what can be done to enhance the Textbox control to support reactive validation? Well, there are three options available for the control designer. Firstly, the designer can subclass the Textbox class and provide an internal handler for the TextChanged event to check and update the binding source. The second option is to provide an attached property that attaches itself to the TextChanged event of the Textbox and updates the binding source. Finally, an Expression Blend Behaviour can be developed that has a similar effect to the attached property previous. It is worth noting here that the ideal solution should also be compatible with the philosophy behind WPF and Silverlight such that there is a separation between business logic and the visual representation i.e. the control is “skin-able”.

Sub-classing the Textbox

In the days of yore this was the only option available to developers and as the development process was fraught with difficulties and customising GUI was rarely if at all undertaken. However, those who did understand the intricacies of such development were forced to into sub-classing the control. As this experience took time and hence embedded itself into the developer as the process it is easy to see how this mentality is extended into the WPF/Silverlight world.

Ultimately these old tricks result in the following code:

 

using System.Windows.Controls;
using System.Windows.Data;

namespace DatabindingAttachedProperty
{
    /// <summary>
    /// The <see cref="TextChangedSubClass"/> class.
    /// </summary>
    public class TextChangedSubClass : TextBox
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="TextChangedSubClass"/> class.
        /// </summary>
        public TextChangedSubClass()
        {
            TextChanged += TextChangedSubClassTextChanged;
        }

        /// <summary>
        /// Handles the TextChanged event of the TextChangedSubClass control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.TextChangedEventArgs"/> instance containing the event data.</param>
        private static void TextChangedSubClassTextChanged(object sender, TextChangedEventArgs e)
        {
            if (!(sender is TextBox))
            {
                return;
            }

            var tb = sender as TextBox;
            BindingExpression bindingExpression = tb.GetBindingExpression(TextProperty);
            if (bindingExpression != null && bindingExpression.ParentBinding.Mode == BindingMode.TwoWay)
            {
                bindingExpression.UpdateSource();
            }
        }
    }
}

The “one trick Pony” development mentality results in awkward code, extension difficulties and maintenance problems – today as it did back then. However, things have changed (unfortunately this development mentality has not) and today we have better ways of solving the problem of the missing binding update.

TextChanged Dependency Property

The Dependency Property provides a simple programming extension that augments a control with a property directly on the class itself, i.e. the class owns the dependency property and do not have much significance outside the class.

 

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace DatabindingAttachedProperty
{
    /// <summary>
    /// The <see cref="TextChangedBindDependencyProperty"/> class.
    /// </summary>
    public class TextChangedBindDependencyProperty : TextBox
    {
        public static readonly DependencyProperty TextChangedBindProperty =
            DependencyProperty.RegisterAttached("TextChangedBind", typeof (bool),
                                                typeof (TextChangedBindDependencyProperty),
                                                new PropertyMetadata(false, TextChangedBindCallBack));

        /// <summary>
        /// Gets or sets a value indicating whether text changed binding is active.
        /// </summary>
        /// <value><c>true</c> if text changed binding is active; otherwise, <c>false</c>.</value>
        [Description("Enable or disable TextChanged checking for this control.")]
        [Category("TextChangedBindDependencyProperty")]
        public bool TextChangedBind
        {
            set { SetValue(TextChangedBindProperty, value); }

            get { return (bool) GetValue(TextChangedBindProperty); }
        }

        /// <summary>
        /// Texts the changed call back.
        /// </summary>
        /// <param name = "d">The d.</param>
        /// <param name = "e">The <see cref = "System.Windows.DependencyPropertyChangedEventArgs" /> instance containing the event data.</param>
        private static void TextChangedBindCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is TextBox)) return;
            var tb = d as TextBox;

            var isb = (bool) e.NewValue;
            if (isb)
            {
                tb.TextChanged += TbTextChangedBind;
            }
            else
            {
                tb.TextChanged -= TbTextChangedBind;
            }
        }

        /// <summary>
        /// Handles the TextChangedBind event of the tb control.
        /// </summary>
        /// <param name = "sender">The source of the event.</param>
        /// <param name = "e">The <see cref = "System.Windows.Controls.TextChangedBindEventArgs" /> instance containing the event data.</param>
        private static void TbTextChangedBind(object sender, TextChangedEventArgs e)
        {
            if (!(sender is TextBox))
            {
                return;
            }

            var tb = sender as TextBox;
            BindingExpression bindingExpression = tb.GetBindingExpression(TextProperty);
            if (bindingExpression != null && bindingExpression.ParentBinding.Mode == BindingMode.TwoWay)
            {
                bindingExpression.UpdateSource();
            }
        }

        /// <summary>
        /// Gets the text changed bind.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <returns></returns>
        public static bool GetTextChangedBind(DependencyObject obj)
        {
            return (bool) obj.GetValue(TextChangedBindProperty);
        }

        /// <summary>
        /// Sets the text changed bind.
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>
        public static void SetTextChangedBind(DependencyObject obj, bool value)
        {
            obj.SetValue(TextChangedBindProperty, value);
        }
    }
}

However, the disadvantage of the Attached Property is that it extends by sub-classing the original control. Hence a conscious decision has to be made in using the sub-classed control over the original. However, the designer will need to have a little mode control, something more flexible that can be use with base classes, third-party classes as well as the classes developed within the project.

TextChanged Attached Property

The Attached Property solution is the first that leaves the TextBox control intact and provides the binding update outside of the implementation. The great benefit of attached properties is that they allow you to extend the functionality of existing controls without having the source code or using extension methods. The attached property can be addressed directly in XAML as well as from the code behind.

namespace DatabindingAttachedProperty
{
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;

    /// <summary>
    /// Definition of the <see cref = "TextChangedInteractor" /> class.
    /// </summary>
    public class TextChangedInteractor : DependencyObject
    {
        /// <summary>
        /// Using a DependencyProperty as the backing store for TextChanged. This enables animation, styling, binding, etc…
        /// </summary>
        public static readonly DependencyProperty TextChangedProperty =
            DependencyProperty.RegisterAttached("TextChanged", typeof (bool), typeof (TextChangedInteractor),
                                                new PropertyMetadata(false, OnTextChangedChanged));

        /// <summary>
        /// The validation Regex.
        /// </summary>
        public static readonly DependencyProperty ExpressionProperty = DependencyProperty
            .RegisterAttached(
                "Expression",
                typeof (string),
                typeof (TextChangedInteractor),
                new PropertyMetadata(string.Empty));

        /// <summary>
        /// Runs test for get Regex.
        /// </summary>
        /// <param name = "obj">
        /// The obj parameter.
        /// </param>
        /// <returns>
        /// The get Regex entry.
        /// </returns>
        public static bool GetTextChanged(DependencyObject obj)
        {
            return (bool) obj.GetValue(TextChangedProperty);
        }

        /// <summary>
        /// Runs test for set Regex.
        /// </summary>
        /// <param name = "obj">
        /// The obj parameter.
        /// </param>
        /// <param name = "value">
        /// If set to <c>true</c> if value.
        /// </param>
        public static void SetTextChanged(DependencyObject obj, bool value)
        {
            obj.SetValue(TextChangedProperty, value);
        }

        /// <summary>
        /// Runs test for on Regex entry.
        /// </summary>
        /// <param name="textChanged">The TextChanged parameter.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnTextChangedChanged(DependencyObject textChanged, DependencyPropertyChangedEventArgs e)
        {
            if (!(textChanged is TextBox))
            {
                return; // support only Regex entry in a TextBox
            }

            var textBox = textChanged as TextBox;

            // add the event handles for key press
            if ((bool) e.NewValue)
            {
                textBox.TextChanged += TextBoxPreviewTextInput;
            }
            else
            {
                textBox.TextChanged -= TextBoxPreviewTextInput;
            }
        }

        /// <summary>
        /// Handles the PreviewTextInput event of the textBox control.
        /// </summary>
        /// <param name = "sender">The source of the event.</param>
        /// <param name = "textChangedEventArgs">The <see cref = "System.Windows.Controls.TextChangedEventArgs" /> instance containing the event data.</param>
        private static void TextBoxPreviewTextInput(object sender, TextChangedEventArgs textChangedEventArgs)
        {
            if (!(sender is TextBox))
            {
                return;
            }

            var tb = sender as TextBox;
            var bindingExpression = tb.GetBindingExpression(TextBox.TextProperty);
            if (bindingExpression != null && bindingExpression.ParentBinding.Mode == BindingMode.TwoWay)
            {
                bindingExpression.UpdateSource();
            }
        }
    }
}

Expression Blend Behaviour

Expression Blend is the only design tool for the successful development of rich UIs in both WPF and Silverlight. Primarily a designer’s tool it can still be enhanced to support technical extensions. Blend’s extension mechanism is achieved through Behaviours. Similar in effect to the Attached Property solution, Blend Behaviours leave the base class intact and

using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Interactivity;

namespace DatabindingAttachedProperty
{
    /// <summary>
    /// The <see cref="TextChangedBehavior"/> class.
    /// </summary>
    public class TextChangedBehavior : Behavior<TextBox>
    {
        /// <summary>
        /// Called after the behavior is attached to an AssociatedObject.
        /// </summary>
        /// <remarks>Override this to hook up functionality to the AssociatedObject.</remarks>
        protected override void OnAttached()
        {
            base.OnAttached();

            // Insert code that you would want run when the Behavior is attached to an object.
            AssociatedObject.TextChanged += TextChanged;
        }

        /// <summary>
        /// Handles the TextChanged event of the AssociatedObject control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.TextChangedEventArgs"/> instance containing the event data.</param>
        protected void TextChanged(object sender, TextChangedEventArgs e)
        {
            if (!(sender is TextBox))
            {
                return;
            }

            var tb = sender as TextBox;
            BindingExpression bindingExpression = tb.GetBindingExpression(TextBox.TextProperty);
            if (bindingExpression != null && bindingExpression.ParentBinding.Mode == BindingMode.TwoWay)
            {
                bindingExpression.UpdateSource();
            }
        }

        /// <summary>
        /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
        /// </summary>
        /// <remarks>Override this to unhook functionality from the AssociatedObject.</remarks>
        protected override void OnDetaching()
        {
            base.OnDetaching();

            // Insert code that you would want run when the Behavior is removed from an object.
            AssociatedObject.TextChanged -= TextChanged;
        }
    }
}

The test program consists of the four TextBox options and associated error processing. Entering a character in one text boxes results in the character being shown in each of the other text boxes. This shows that the binding is taking place on every keystroke and not just on the focus changing as is normal in Silverlight.

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:DatabindingAttachedProperty="clr-namespace:DatabindingAttachedProperty"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    x:Class="DatabindingAttachedProperty.MainPage"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="604">
    <Grid
        x:Name="LayoutRoot"
        Background="White"
        DataContext="{Binding Source={StaticResource Locator}}">
        <StackPanel Margin="100,30,300,0" Orientation="Vertical" d:LayoutOverrides="Height">
            <DatabindingAttachedProperty:TextChangedBindDependencyProperty
                x:Name="textChangedDependencyProperty"
                Height="36"
                TextWrapping="Wrap"
                Text="{Binding Main.TextDetails, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" 
                TextChangedBind="True"
                 Margin="0,0,0,10" />
            <TextBox
                x:Name="textBox1"
                Height="36"
                TextWrapping="Wrap"
                Text="{Binding Main.TextDetails, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" 
                Margin="0,0,0,10"
            />
            <TextBox
                x:Name="textBox"
                TextWrapping="Wrap"
                Text="{Binding Main.TextDetails, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" 
                Height="36" 
                d:LayoutOverrides="Height" 
                Margin="0,0,0,10">
                <i:Interaction.Behaviors>
                    <DatabindingAttachedProperty:TextChangedBehavior />
                </i:Interaction.Behaviors>
            </TextBox>
            <DatabindingAttachedProperty:TextChangedSubClass
                x:Name="textChangedSubClass"
                TextWrapping="Wrap"
                Text="{Binding Main.TextDetails, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}"
                DatabindingAttachedProperty:TextChangedInteractor.TextChanged="true"
                Height="36" 
                Margin="0,0,0,10" />
        </StackPanel>
    </Grid>
</UserControl>

The ViewModel contains validation for itself as well as the Model.

using System.ComponentModel;
using System.Linq;
using DatabindingAttachedProperty.Model;
using DatabindingAttachedProperty.Validation;
using FluentValidation.Results;
using GalaSoft.MvvmLight;

namespace DatabindingAttachedProperty.ViewModel
{
    /// <summary>
    /// The <see cref="MainViewModel"/> class.
    /// </summary>
    public class MainViewModel : ViewModelBase, IDataErrorInfo
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="MainViewModel"/> class.
        /// </summary>
        public MainViewModel()
        {
            Model = new MainModel();
        }

        /// <summary>
        /// Gets or sets the text details.
        /// </summary>
        /// <value>The text details.</value>
        public string TextDetails
        {
            get { return Model.TextDetails; }
            set
            {
                if (Model.TextDetails == value)
                {
                    return;
                }

                Model.TextDetails = value;
                RaisePropertyChanged("TextDetails");
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is valid.
        /// </summary>
        /// <value><c>true</c> if this instance is valid; otherwise, <c>false</c>.</value>
        public bool IsValid
        {
            get { return SelfValidate().IsValid; }
        }

        /// <summary>
        /// Gets or sets the model.
        /// </summary>
        /// <value>The model.</value>
        protected MainModel Model { get; set; }

        #region Implementation of IDataErrorInfo

        /// <summary>
        /// Gets a message that describes any validation errors for the specified property or column name.
        /// </summary>
        /// <returns>
        /// The validation error on the specified property, or null or <see cref="F:System.String.Empty"/> if there are no errors present.
        /// </returns>
        /// <param name="columnName">The name of the property or column to retrieve validation errors for.</param>
        public string this[string columnName]
        {
            get
            {
                ValidationResult validationResults = SelfValidate();

                if (validationResults == null) return string.Empty;

                ValidationFailure columnResults =
                    validationResults.Errors.FirstOrDefault(x => string.Compare(x.PropertyName, columnName) == 0);

                return columnResults != null ? columnResults.ErrorMessage : string.Empty;
            }
        }

        /// <summary>
        /// Gets a message that describes any validation errors for the object.
        /// </summary>
        /// <returns>
        /// The validation error on the object, or null or <see cref="F:System.String.Empty"/> if there are no errors present. 
        /// </returns>
        public string Error
        {
            get { return ValidationHelper.GetError(SelfValidate()); }
        }

        #endregion

        /// <summary>
        /// Validates the ViewModel and Model.
        /// </summary>
        /// <returns></returns>
        public ValidationResult SelfValidate()
        {
            ValidationResult vr1 = ValidationHelper.Validate<MainViewModelValidator, MainViewModel>(this);
            ValidationResult vr2 = ValidationHelper.Validate<MainModelValidator, MainModel>(Model);

            foreach (ValidationFailure failure in vr2.Errors)
            {
                vr1.Errors.Add(failure);
            }

            return vr1;
        }
    }
}

The Model contains only one property.

namespace DatabindingAttachedProperty.Model
{
    /// <summary>
    /// The <see cref="MainModel"/> class.
    /// </summary>
    public class MainModel
    {
        /// <summary>
        /// Gets or sets the text details.
        /// </summary>
        /// <value>The text details.</value>
        public string TextDetails { get; set; }
    }
}

The validation relies on Fluent Validation package and the validators for both the ViewModel and the Model are shown below.

using DatabindingAttachedProperty.ViewModel;
using FluentValidation;

namespace DatabindingAttachedProperty.Validation
{
    /// <summary>
    /// The <see cref="MainViewModelValidator"/> class.
    /// </summary>
    public class MainViewModelValidator : AbstractValidator<MainViewModel>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="MainViewModelValidator"/> class.
        /// </summary>
        public MainViewModelValidator()
        {
            RuleFor(model => model.TextDetails).NotNull().Matches(@"^[0-9]+$").WithMessage("Not a number.");
        }
    }
}

 

using DatabindingAttachedProperty.Model;
using FluentValidation;

namespace DatabindingAttachedProperty.Validation
{
    /// <summary>
    /// The <see cref="MainModelValidator"/> class.
    /// </summary>
    public class MainModelValidator : AbstractValidator<MainModel>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="MainModelValidator"/> class.
        /// </summary>
        public MainModelValidator()
        {
            RuleFor(model => model.TextDetails).NotNull().WithMessage("Must hold a value.");
        }
    }
}

In conclusion, four options have been put forward as successful in solving the missing property changed binding that exists in WPF but not in Silverlight4. The first two methods of extending the base class invasively are not recommended as the full design flexibility are non-existent. The Attached Property solution as well as the Blend Behaviour solution are, by far, the correct way to approach a solution. Personally, I find that only the latter two options should be considered – but then I am a believer in the WPF and Silverlight design philosophy and hope to rid myself of the burden of the VB control development word someday.

That’s all Folks…

Balsamiq – First Thoughts

•January 8, 2012 • Comments Off

Over the last year or more I have been looking for a simple, low cost, but powerful wire-framing design tool. On a couple of occasions I have worked on projects where Balsamiq was being used as the wire-frame design tool. I was always impressed with the tool and how simple it was to put together simple, low-fi GUI mock-ups. However, I wrote the tool off as being too expensive for my irregular usage due to it being used in large corporate projects – a mistake on my part to think that all corporate software was expensive and hence Balsamiq would also be so.

Recently I was working on a Silverlight project where the business analysts were defining the rudimentary GUI wire-frames and I was asked to provide some support on setting out the GUI design. After sitting together for about an hour with a colleague we had managed not only to define the static layout of a form but we had also added a considerable amount of the interaction associated with the form with respect to the button functionality and the associated sub-screens and dialogs. We then exported the PDF rendering of the form’s rudimentary workflow and attached this document to the User Story with TFS.

I was very impressed with what could be accomplished in such a short time.

Later I decided to look deeper, to take a deeper dive as we say these days, into the product. The first point that struck me was the cost of the product – I was amazed that such a powerful product could be sold for such a small cost. Finally, a tool was in my meagre budget. With no second thoughts I purchased to product without downloading the trial version. I was convinced.

Positive

Here are just a number of the big hits in Balsamiq:

Negative

Of course all products have their drawback and Balsamiq has a couple that make it difficult to use. But only a couple. For those interested I find that the lack of internal version control or support for an external product and the lack of a meta-diagram showing the linking between related screen mock-ups difficulties but not show-stoppers.

Conclusion

There is very little more than that I thoroughly recommend Balsamiq to anyone that wishes to design mock-ups for an application or product. I have used the basic low-fi functionality as well as using Balsamiq in hi-fi design mock-ups (but more to that in a later blog entry). The cost is very affordable and the associated website and support from Balsamiq as well as the community is excellent.

Just go out and buy it.

That’s all Folks…

Usability – Amount Ordering Control (Part 2)

•December 27, 2011 • Comments Off

In the first part of this mini-series I set out the basic problem and made the first sketch of a solution. In this next part I will open up the design and discuss how the parts are put together the components required to finalise the solution. The wireframe of the solution is shown below. There are only three items in the list, however it can be imagined that this will increase over time and that some sort of list would suffice. As we can fully style the list items the possibility of showing a graphic as well as a selection button or check-box is a simple matter. The amount field will be a textbox that only allows the entry of numeric characters based on the order increment value. Range input will be in the form of a slider that indicates the min, max and warning ordering amount levels associated with the selected item. Additionally the slider shall be colour coded to indicate the okay, warning and error ranges using green, amber and red accordingly. There is an interaction between the numeric input and the slider such that changes in one will result in changes in the XX changes in the other. With respect to the Order button, it will only be enabled when an item is selected and a valid selection has been made in either the amount field or using the slider. During access to the database, either during loading or saving, the control “real-estate” will be disabled using a busy indication of some sort. The basic design can be seen below.

Forget Programmability think Usability

Now let us consider the essential part of the design – the usability. Normally, this type of dialog with the user would be split into either a reactive dialog allows the user to enter anything into the conversation and have the validation take place after the Order button has been pressed or a proactive where errors are indicated at that time they happen. In this case a proactive design will disable the Order button whenever the data input conflicts a rule or constraint. For example, entering a value greater than the clearly indicated maximum allowed amount or that no decision has been made as to which item should be selected.

I will reject the reactive design as it makes the user feel “naughty” or “foolish” having entered data that is invalid. Moreover, the user is frustrated in the sense that their time has been wasted entering data only to find that out at a later stage. However, the proactive approach may also lead to user annoyance if the proactive feedback is in anyway “aggressive” i.e. messages incorrectly phrased or the use of harsh colours (especially red in western society).

To overcome the above issues I will inform the user as to the aim of the dialog and its operation up front. This can be achieved using a banner description above the active dialog content similar to that found in Microsoft Money. The proactive validation feedback will be displayed interactively reinforcing the aims of the dialog. In this case exceeding the maximum will result in the Order button being disabled and a text enforcing this – “The maximum amount has been exceeded. Please reduce your wished amount below XX to enable ordering of the YY item”. Similarly for the selection of an item in the list of possible choices could be similar to “Currently no item has been selected. Your order cannot be processed until an item from the above list has been selected”. The banner description will therefore be along the lines of “Your order cannot be processed until an item has been selected from the list of available items and that the wished amount does not exceed the maximum allowable. Order amounts that are above those normally encountered but do not exceed the maximum will be possible. However, those amounts will be displayed as lying in the amber area of the amount indicator.”

The final validation handling will only result in a friendly and helpful message being displayed and the Order button being disabled and the user is free to enter whatever values they wish and to make a conscious decision on ordering more than the normally ordered amounts.

One last usability consideration come when the number of options available to choose from cannot be displayed given the real-estate available for those items. The problem is such; given that the available real-state for the items will only allow three to be displayed at a time and that more than that number of items that are available for selection is significantly more, 20 say, how will the currently selected item remain in focus when the user scrolls away such that the currently selected item moves out of view? The approach taken here is that of elasticity, i.e. the selected item will be pulled back into view after a certain inactivity delay and that the selected item is out of view.

Finally, we need only to consider the placement of the helpful and dynamic informational message. Attaching the message to the display element in error leads to the user searching the dialog for an entry field in error. More helpful is to situate the message close to the “acceptance” input, in this case the Order button. Hence this message will appear either above or below the Order button as this button will have the user’s focus when the user believes that the dialog has been correctly filled out.

 

Usability – Amount Ordering Control (Part 1)

•November 14, 2011 • Comments Off

The Challenge

I have been giving some thoughts to a nagging problem that I have encountered recently. The problem can be described so as follows: “The user should be able to order an item in a certain amount. The item must be selected from a list of available items. The amount can only be selected as a multiple of a base value. A warning message will be displayed when the selected amount exceeds a given warning level. An error message will be displayed when the user selects an amount which is greater than a defined maximum. Thereafter the user can confirm the order by selecting ‘Order’” The items being ordered are small regularly shaped, coloured pieces of plastic. Additionally, there are other constraints such that the user will only see the warning message once “Order” has been selected, the number of items to select will not be greater than 5-6, and that amounts that are greater than the maximum amount will be immediately indicated and the “Order” option be disabled. This is pretty simple to develop from the look of it.

The first design (and possibly the final one as well) could be as follows:

However, there seems to be some usability problems in my opinion. Firstly, the user is only informed of warning levels upon ordering but has immediate feedback when the maximum has been exceeded. Warning levels and maximum levels should be communicated consistently, that means either both immediately or both once “Order” has been selected. A further problem could arise with the selection of the wished item. As the items are coloured and the number of possibilities are small a combo box would suffice. However, users are more likely to select the correct item quicker based on the colour and shape than from an item in a combo box. If the requirement was more complex such that a large number of items could appear then a list or flow-panel can be employed. The major point here is that the user sees as many of the possibly selectable items as space allows. Utilising the size of image and text can lead to more being shown.

Analysing the data involved we see that there are minimum, maximum, increment and warning values associated with the items. Here we could indicate the increment to the user rather than having to guess it by entering values until the error message disappears. The minimum, warning and maximum values can also be displayed. As these values are quasi-static labels would be appropriate.

Proposed Solution

As above the user should be able to enter the wanted amount. The user should be presented with a visual indication of what can be selected. As only one item can be select at any one time the selection can be based on a set of styled radio buttons which would include a graphic representing the actual item. What is left is only bringing the warning and error levels together in a consistent form. Using colours that we normally associate with traffic lights we can indicate that the entered amount lies in the correct ranges. Additionally, a slider can be used to allow the user move to a wished point or, more importantly, that the entered value falls in a certain area. Here a colour banding above the slider would be an appropriate choice.

The final design looks similar to that shown below:

The next part of this design exercise will focus on how construct such a control for Silverlight and/or WPF.

That’s all folks…

Adobe Installer Progress Bar

•October 20, 2011 • Comments Off

I am not really sure why I like it but the visual design of the Adobe installer for the Flash Player just looks amazing. Personally, the colours are just right, great attention has been given to borders, and the form is striking. Most of all, the progress bar is something to die for. It is sleek, visually strong and gets the job done with a minimum of animation. This is the screen I am talking about:

Right, I have been challenged. I want to be able to have a progress bar like this one in my portfolio. So, how did I go about doing it? Just read on to find out.

Getting the colour scheme

I pulled out my faithful graphics editor Paint Shop Pro X and go to work on the snapshot made of the above installer screen with SnagIt. Firstly, I isolated the primary colours used

The next area I concentrated on was the gradients used for both the progress bar as well as the button. For the progress bar I isolated three distinct gradients; firstly, the inner border the fades from top to bottom. Secondly, the top gradient of the main body of the progress bar, and finally the bottom gradient. The latter two will be combined into one gradient within Expression Blend as described below. The button has colours and gradients as follows:

From this “analysis” I ended up with the following colour chart for the complete dialog.

The Colour Chart

 

(Re)Styling the Progress Bar

The simplest thing to do with the Progress Bar is to edit a copy of the current style in Blend. Once in the editor the new style must be given an outside border as well as an inner gradient for the unfilled are of the progress bar. The progress bar itself has its own gradient applied. These gradient are either given as the style properties or they are statically referenced from the Colurs.xaml resource.

(Re)Styling the Button

The button has a number of states associated with its operation. MouseOver, Selected, Disabled and Focussed have been adjusted such that they behave in the same way as the Adobe button does, however there may be some slight differences in operation. The major change is the focus blue border that appears around the button. This was achieved using a negative margin for two XAML border elements that encapsulated the buttonand had their border sizes set to one and single colour to each hence giving the feeling that the is a gradient in use. Note that he content holder has a drop shadow applied to the contents thus hinting floating text effect.

Conclusion

As this project is a learning one I do not expect to exactly mimic the Adobe controls – it is left as an exercise to the reader to make the final adjustments here :-) . The only thing that is left is to place the original with my mockup side to side

 

 

By the way, all of this was achieved without a single line of program code! As usual the code for the colours can be found here, the styles here, and the main window code here.

That’s all Folks…

 
Follow

Get every new post delivered to your Inbox.