Latest Entries

Design pattern: Exporting interactions

Created on 5/11/2013 10:13:21 PM, last edited 5/12/2013 12:29:37 PM

This is the first article in a series where I will present a new design pattern in each article. My initial plan is to have each article consist of three sections: What?, Why?, and How?. The What? section presents the idea with some examples, the Why? section provides a motivation for using the pattern, and the How? section details an example implementation. So without further ado, here is the first article on exporting interactions.

Figure 1. A schematic diagram showing the design pattern for the example of a simple blog-entry editor with two actions.

What?

The goal is to create a separation between the business logic of actions (example actions would be "save" or "open") and the visual presentation (for example buttons) by having components export descriptions of their actions instead of actually presenting them visually within their own UI. This is shown schematically in Figure 1. As an example, consider a very simple blog-entry editor dialog (see Figure 2). The dialog consists of a form with a few fields and a couple of actions: one action to save the changes, and one to open a preview of the blog entry. According to this design pattern, the blog-entry editor component (which is the content of the dialog) should contain the visual representation of the form, but not that of the two actions. Instead, two action descriptions should be "exported" by the editor and visualized by the parent component, which is in this case is the window/dialog control. It is then the responsibility of the component which hosts the entry editor to create visual representations of the actions and invoke them when appropriate (for example when a button is clicked). The entry editor need only be concerned with the implementation of the code executed when the actions are invoked. In Figure 2, the blog-entry editor is hosted by a dialog control where the actions are presented at the bottom of the window. The same blog-entry editor component is seen hosted by a different control in Figure 3, where the actions are presented in a bar at the top of the screen.

Figure 2. An example dialog for editing blog entries.

Figure 3. An example "page" for editing blog entries.

One can also include structure in the exported interactions with which the host component can generate menus or some other presentation of the structured data. A general approach is to export a tree of interaction nodes, some of which are actions and some of which are just structural. This allows the pattern to be used for navigation as well. An example of this is shown in Figure 4. The nodes Jobs and Survey in the popup menu serve only to provide structure, whilst All Jobs, Task List, Definitions, and Question Templates are action node which in this case are used to navigate to different contents. The actions Add job and Open are exported by the current content, but merged together with the other interactions to give a coherent feel.

Figure 4. An example of exported interactions with structure.

Why?

Here are a few of the advantages of using this design pattern:

  • Provides a consistent UI design for the presentation of actions throughout the application.
  • When working on a new component, a lot of time is saved by not having to worry about the presentation of actions.
  • The UI for presentation of actions can be easily changed without modifying any of the existing components.
  • The additional abstraction makes the development of new components easier, which can be useful when introducing new developers to a project.
  • Different methods can be used for presenting the actions depending on the context. The examples above in Figures 1 and 2 demonstrate this very well (the same component is viewed both in a dialog and in a "page").
  • Having all actions defined in this way may be useful when documenting a system.

How?

For the sake of simplicity I shall only consider the most basic version of this design pattern here. In a real implementation, such as the one we have at StatusInfo, one can add lots of features, tweaks, and improvements. The act of exporting the interactions can be done in a very simple way. A clear and concise interface such as the following will do the trick:

public interface IInteractionExporter
{
     IEnumerable InteractionItems { get; }
}

Listing 1. The interface which classes should implement if they export interactions.

Interactions are exported in an enumerable collection of elements of the InteractionItem class. The rest of the magic lies in what one stuffs into the InteractionItem class and obviously the methods used to render the interactions. A simple yet useful InteractionItem might look something like this:

public class InteractionItem
{
    public InteractionItem(Action<object> action) 
    {
        if action == null)
        {
            throw new ArgumentNullException("action");
        }
        this.executeCommand = new GenericCommand<object>(action);
    }

    public string Name { get; set; }
    public string Description { get; set; }
    public object ImageSource { get; set; }
    public Visibility Visibility { get; set; }
    public ICommand ExecuteCommand 
    {
        get { return this.executeCommand; }
    }

    private GenericCommand<object> executeCommand;
}

Listing 2. An example interaction item class. In a real implementation one would implement INotifyPropertyChanged and also have a few more constructors. Such details have been left out for brevity. See Tip of the day: Generic Command for the GenericCommand<T> class.

In a real implementation one should definitely implement INotifyPropertyChanged so that interaction items can be dynamically modified. In addition to that, there are a ton of various features one can add depending on the usage, such as types or flags for emphasizing certain interactions etc. If one wishes to have structured interactionsm some sort of Children property can be added with all the child nodes.

In the current example we have a Name property, which might be "Save" for instance; a Description property, which might say "Saves all changes by persisting them to the database."; an ImageSource property which may contain an icon to display; and a Visibility property which can be used to hide actions when they are not applicable. The final property is an ICommand which should be executed in order to invoke the action.

It is now straightforward to present these actions visually using for example XAML. A very simple action presenter can be obtained by binding the collection of exported interaction items to an ItemsControl and adding a Button for each item in the collection. The Command property of each Button is directly bound to the ExecuteCommand property of each InteractionItem instance, and the Name, Description, and ImageSource properties are used to present a label, a tooltip, and an icon for each button. This example is presented below:

<ItemsControl ItemsSource="{Binding InteractionItems}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Command="{Binding ExecuteCommand}"
                    Visibility="{Binding Visibility}" 
                    ToolTipService.ToolTip="{Binding Description}">
                <StackPanel Orientation="Horizontal">
                    <Image Source="{Binding ImageSource}" />
                    <TextBlock Text="{Binding Name}" />
                </StackPanel>
            </Button>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Listing 3. An example action presenter. Please note that this XAML is for demonstrative purposes only and has been significantly simplified for brevity.

Conclusions

I hope that others will find this design pattern interesting, I have personally found it very useful. The design is very open for new ideas and extensions, so please feel free to share any ideas you may have in the comments.

Comments

Leave a comment