Archive

Posts Tagged ‘WPFGlue’

Implementing the Sticky Command Design Pattern

February 13, 2010 1 comment

The Sticky Command design pattern is one of the patterns in WPFGlue which allow to add custom functionality to out-of-the-box WPF controls. Adding a Sticky Command to a FrameworkElement gives it a certain new behaviour, and makes this behaviour available to the element and all its child elements through a routed command, while the implementation of the element remains separate and independent of the implementation of the behaviour.

Let’s take an example. A very common need in data oriented applications is a submit command which sends the values of a group of controls to the underlying data store. This command should be disabled when the data is invalid, and it should be possible to connect it to a KeyGesture which allows to call the command by pressing a given key when entering data.

<GroupBox x:Name="CustomerGroupBox" Header="Customer"
          v:Submit.Command="{StaticResource SubmitCommand}"
          v:Submit.KeyGesture="Enter"> <!—- Content left out for clarity -->
</GroupBox>

The Sticky Command is stuck to the GroupBox by setting the Submit.Command Sticky Property. Optionally, one can add a KeyGesture which invokes the command, in this case pressing the Enter key. The SubmitCommand is just a standard RoutedCommand:

<Window.Resources>
    <RoutedCommand x:Key="SubmitCommand"/>
</Window.Resources>

By itself it doesn’t provide any functionality; it’s just kind of an identifier for the behaviour we want to add to the GroupBox.

Creating a Sticky Property

A Sticky Property is an attached property that, in addition to storing a value on the target element, does some work in its PropertyChanged handler. In our case, this work consists of creating a CommandBinding and setting it on the target element, or removing the created CommandBinding, respectively.

Public Class Submit
    Inherits DependencyObject

    Public Shared ReadOnly CommandProperty As DependencyProperty = _
            DependencyProperty.RegisterAttached("Command", _
            GetType(RoutedCommand), GetType(Submit), _
            New PropertyMetadata(AddressOf OnCommandChanged))
    Public Shared Function GetCommand(ByVal d As DependencyObject) _
            As RoutedCommand
        Return d.GetValue(CommandProperty)
    End Function
    Public Shared Sub SetCommand(ByVal d As DependencyObject, _
            ByVal value As RoutedCommand)
        d.SetValue(CommandProperty, value)
    End Sub
    Private Shared Sub OnCommandChanged(ByVal d As DependencyObject, _
        ByVal e As DependencyPropertyChangedEventArgs)
        Dim f As FrameworkElement = TryCast(d, FrameworkElement)
        If f IsNot Nothing Then
            If e.OldValue IsNot Nothing Then
                Detach(f, e.OldValue)
            End If
            If e.NewValue IsNot Nothing Then
                Attach(f, e.NewValue)
            End If
        End If
    End Sub
'...
End Class

The implementation of OnCommandChanged is quite simple: if the property already has a value, the command should be detached from the target, and if a new value is provided, this value should be attached to it. One might ask why it is necessary to provide a Detach procedure as well. Why not just leave the CommandBinding in place? If the command can be removed by changing setting the value of Submit.Command to Nothing, then the command can be attached and detached through triggers, which opens up a whole new line of uses…

Attaching and Detaching the CommandBinding

Private Shared Sub Attach(ByVal d As FrameworkElement, _
                          ByVal command As RoutedCommand)
    d.CommandBindings.Add(New SubmitCommandBinding(command))
    Dim gesture As KeyGesture = GetKeyGesture(d)
    AttachKeyGesture(d, command, gesture)
    If d.BindingGroup Is Nothing Then
        d.BindingGroup = New BindingGroup
    End If
End Sub
Private Shared Sub Detach(ByVal d As FrameworkElement, _
                          ByVal command As RoutedCommand)
    For Each b As SubmitCommandBinding In _
            d.CommandBindings.OfType(Of SubmitCommandBinding)()
        d.CommandBindings.Remove(b)
    Next
    DetachKeyGesture(d)
End Sub

The Attach procedure creates a new CommandBinding that connects the provided RoutedCommand to its implementation, and adds it to the targets CommandBindings collection.

The Detach procedure removes the CommandBinding from the collection. In order to be able to find the correct CommandBinding, Attach uses a class derived from CommandBinding, in order to use its type as marker. This way, one doesn’t have to store a reference to the created CommandBinding in order to be able to remove it later. The dummy class is a private nested class inside the Submit class:

Private Class SubmitCommandBinding
    Inherits CommandBinding
    Public Sub New(ByVal command As RoutedCommand)
        MyBase.New(command, AddressOf OnExecutedSubmit, _
                   AddressOf OnCanExecuteSubmit)
    End Sub
End Class

The Command’s Implementation

The procedures OnExecutedSubmit and OnCanExecuteSubmit handle the RoutedCommand.CanExecute and RoutedCommand.Executed events that are sent out by the CommandBinding. It is useful to separate the code specific to event handling from the code that does the actual work:

Private Shared Sub OnCanExecuteSubmit(ByVal sender As Object, _
        ByVal e As CanExecuteRoutedEventArgs)

    Dim result As Boolean = False
    Dim target As FrameworkElement = TryCast(sender, FrameworkElement)
    If target IsNot Nothing Then
        ' Separate event specific code from domain specific code...
        result = CanExecuteSubmit(target,e.Parameter)
    End If
    e.CanExecute = result
    e.Handled = True
End Sub

Public Shared Function CanExecuteSubmit(ByVal target As FrameworkElement, _
        ByVal parameter As Object) As Boolean
    Dim result As Boolean = False
    If target IsNot Nothing Then
        result = (target.BindingGroup IsNot Nothing AndAlso Not _
                  System.Windows.Controls.Validation.GetHasError(target))
    End If
    Return result
End Function

Private Shared Sub OnExecutedSubmit(ByVal sender As Object, _
                                    ByVal e As ExecutedRoutedEventArgs)
    Dim target As FrameworkElement = TryCast(sender, FrameworkElement)
    If target IsNot Nothing Then
        If CanExecuteSubmit(target, e.Parameter) Then
            ExecuteSubmit(target, e.Parameter)
        End If
        e.Handled = True
    End If
End Sub

Public Shared Sub ExecuteSubmit(ByVal target As FrameworkElement, _
        ByVal parameter As Object)
    target.BindingGroup.UpdateSources()
End Sub

Providing a KeyGesture

In order to be able to specify a KeyGesture for the command on the target, we need to create a second Sticky Property, which is able to add the KeyGesture to the target’s InputBindings collection. The method is similar to the one used with the CommandBinding itself. However, there is one point of note: We cannot be sure of the order in which the attached properties are set on the target. So, we have to make sure that CommandBinding and InputBinding are set up correctly no matter which is specified first. Since the InputBinding depends on the CommandBinding, one could say that Submit.Command is the main Sticky Property, while Submit.KeyGesture is a supporting Sticky property. The rule would then be that the Attach and Detach procedures for the main Sticky property would have to call the Attach procedures for all supporting properties in turn, while the Attach procedures of the supporting properties only attach something if the main Sticky Property has already been set.

The implementation of the KeyGesture functionality looks like this:

Public Shared ReadOnly KeyGestureProperty As DependencyProperty = _
        DependencyProperty.RegisterAttached("KeyGesture", _
                    GetType(KeyGesture), GetType(Submit), _
                    New PropertyMetadata(AddressOf OnKeyGestureChanged))
Public Shared Function GetKeyGesture(ByVal d As DependencyObject) _
        As KeyGesture
    Return d.GetValue(KeyGestureProperty)
End Function
Public Shared Sub SetKeyGesture(ByVal d As DependencyObject, _
                                ByVal value As KeyGesture)
    d.SetValue(KeyGestureProperty, value)
End Sub
Private Shared Sub OnKeyGestureChanged(ByVal d As DependencyObject, _
        ByVal e As DependencyPropertyChangedEventArgs)
    Dim f As FrameworkElement = TryCast(d, FrameworkElement)
    If f IsNot Nothing Then
        If e.OldValue IsNot Nothing Then
            DetachKeyGesture(f)
        End If
        If e.NewValue IsNot Nothing Then
            AttachKeyGesture(f, GetCommand(f), e.NewValue)
        End If
    End If
End Sub
Private Shared Sub AttachKeyGesture(ByVal d As FrameworkElement, _
                                    ByVal command As RoutedCommand, _
                                    ByVal gesture As KeyGesture)
    If command IsNot Nothing And gesture IsNot Nothing Then
        d.InputBindings.Add(New SubmitKeyBinding(command, gesture))
    End If
End Sub
Private Shared Sub DetachKeyGesture(ByVal d As FrameworkElement)
    For Each i As SubmitKeyBinding In _
            d.InputBindings.OfType(Of SubmitKeyBinding)()
        d.InputBindings.Remove(i)
    Next
End Sub

Private Class SubmitKeyBinding
    Inherits InputBinding
    Public Sub New(ByVal command As RoutedCommand, _
            ByVal gesture As KeyGesture)
        MyBase.New(command, gesture)
    End Sub
End Class

Reusability

Once we have this submit command, we can reuse it as it is, in any project, with any kind of control or data. But what about reusability of the pattern implementation itself?

The whole Submit class consists of static members, only. This has the advantage of not creating dependent object references with the command bindings, which could interfere with the garbage collection of the page on which the command is used. Unfortunately, shared members cannot be overridden, which means that it is not straight forward to create a common base class for Sticky Commands and derive new implementations from that class. However, the domain specific code and the pattern specific code are quite easy to separate into different procedures, so that it might be an option to use Item Templates or Code Snippets in order to reuse the pattern specific code.

Conclusion

The Sticky Command pattern offers a powerful and flexible way of modifying the behaviour of standard controls without changing their implementation. Because it is used through declarative syntax, it can leverage the full power of WPF style, trigger and template mechanisms. In addition to that, a new implementation of the pattern can be created from an existing one with minimal changes.

Downloads

The example solution on the Downloads page contains a project called SubmitCommandExample which has the complete code for this example.

Advertisements

The Sticky Component Framework

December 11, 2009 3 comments

What is a Sticky Component? A Sticky Component is a component that can be attached to any FrameworkElement or FrameworkContentElement in order to enhance its functionality, without the need to subclass the element or to write code behind for it. Because of this, Sticky Components can be used very effectively to encapsulate specialized behaviours in a reusable way, and to enhance either the View or the ViewModel of an MVVM application without changing its code.

Sticky Component Interaction Patterns

In order to enhance the functionality of an element, the Sticky Component needs to interact with the element. There are several possible ways to connect the two:

  • Through registering event handlers: The Sticky Component can subscribe to events of the element it is attached to, and trigger its own functionality through these events.
  • Through registering CommandBindings: The Sticky Component can add its own CommandBindings to the element’s CommandBindings collection, thus enabling the element to handle the specified command.
  • Through registering InputBindings: the Sticky Component can enable an element to invoke commands by adding InputBindings to its InputBindings collection.
  • Through data binding: the Sticky Component can bind its own properties to the properties of the element. These bindings could in principle have the element as target or as source. But since many properties in the WPF framework are readonly, it is less error prone to always make the Sticky Component the binding target by convention.
  • Through binding to the element’s DataContext: a special class of Sticky Component, the Sticky ViewModel, doesn’t enhance the View, but the ViewModel, by binding to its properties and adding functionality that isn’t present in the ViewModel without the need to change it.

Some of these patterns require references between the Sticky ViewModel and the element it is attached to (its “base”). References are dangerous. They may cause memory leaks and unintended behaviour, e.g. if events are handled even if the view that established the event subscription is already out of scope. Therefore, the core of the Sticky Component Framework is concerned with managing the lifetime of a Sticky Component and its interaction patterns so that all these references are cleaned up when appropriate.

Sticky Component Lifetime

The life cycle of a Sticky Component looks like follows:

  • It is defined and configured in the Resources of the application, a window, or an individual element.
  • It is referenced in an attached property on the base element it is attached to. This is the time when the Sticky Component is actually instantiated.
  • It attaches itself to the base. This can happen either immediately or delayed, depending on whether the base must be in initialized or loaded state before the component can attach to it.

The end of the component’s relationship to the base could come in two ways:

  • Either the attached property which connects the component to the base is reset,
  • or the base itself is unloaded.

In both cases, all references between the Sticky Component and its base should be removed, leaving either object ready for garbage collection. If the component still exists after it has been detached from its base (e.g. because it is kept as a shared instance in a ResourceDictionary), it could be attached again to a different base, or even the same, if that still is available.

This lifetime pattern is expressed in the following interface definition:

Public Enum AttachMode As Integer
    Immediate = 0
    OnInitialized = 1
    OnLoaded = 2
End Enum

Public Interface IStickyComponent

    Sub OnAttach(ByVal base As Object, ByVal e As EventArgs)

    Sub OnDetach(ByVal base As Object, ByVal e As EventArgs)

    ReadOnly Property Mode() As AttachMode

End Interface

OnAttach will be called whenever the Sticky Component will be attached to a base, OnDetach will be called when it is detached. Both methods have EventHandler signatures, so that they can be invoked by the Initialized, Loaded or Unloaded events, respectively. The Mode property defines when the component should attach itself to the element. If possible, the component should attach itself immediately. However, if it needs to modify existing bindings, it will have to do that during the Initialized event, and if it needs to access properties that are data bound, like e.g. the DataContext of the base, it might have to wait until the Loaded event. Since these requirements depend on what the component does, it would be expected that a class that implements IStickyComponent would return a constant value here.

The StickyComponentManager

The StickyComponentManager is a static class that encapsulates the different ways to establish and remove interaction connections between a Sticky Component and its base. It offers overloaded Attach and Detach procedures in pairs with corresponding parameters. So, one would attach an event to a base using the Attach(base,event,handler) overload, and remove it again using the Detach(base, event,handler) overload. There are overloads for all cases discussed here; some of these overloads offer additional services; e.g. there are overloads for attaching event handlers which automatically remove the event handler after it has fired once (using the One Shot Event pattern), or if another specified event occurs before the event that the handler is supposed to handle.

In your Sticky Component, you would set up the connection to the base by calling the appropriate Attach methods of the StickyComponentManager in your OnAttach implementation, and remove the connection by calling the corresponding Detach methods in the OnDetach implementation.

The most important overloads of these methods are the ones that attach / detach Sticky Components. There is a special implementation of a DependencyPropertyChangedHandler that you can use with your attached properties that attach Sticky Components which calls these overloads:

Public Shared Sub OnStickyComponentChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
    Dim c As IStickyComponent
    If e.OldValue IsNot e.NewValue Then
        c = TryCast(e.OldValue, IStickyComponent)
        If c IsNot Nothing Then
            StickyComponentManager.Detach(d, c)
        End If
        c = TryCast(e.NewValue, IStickyComponent)
        If c IsNot Nothing Then
            StickyComponentManager.Attach(d, c)
        End If
    End If
End Sub

This will ensure that the lifetime of the sticky component is managed according to the life cycle described above.

In addition to the Attach and Detach methods, the StickyComponentManager contains several utility methods which hide the difference between FrameworkElement and FrameworkContentElement when attaching Sticky Components. So, elements derived from both of these classes could be the base for Sticky Components; on other elements, the Attach / Detach methods would simply do nothing.

Using Sticky Components

In XAML, you would normally declare and configure a Sticky Component in a Resources section, like this:

    <ex:TestStickyPatterns x:Key="UseEvents"
        Name="UseEvents" UseCommand="False"/>
</Page.Resources>

This would define a Sticky Component of class TestStickyPatterns and configure it by setting its Name and UseCommand properties.

You would then use it on a base element like this:

    <Button x:Name="TestEventPatternsButton"
          ex:TestStickyPatterns.Component="{StaticResource UseEvents}">
    Test Event Patterns</Button>

 

If you need the Sticky Component more than once on your page, consider setting the x:Shared attribute to false on its declaration. Thus you make sure that each time the component is used, you start with a fresh instance. Otherwise it could happen that the component is attached to multiple elements on your page at the same time, with unwelcome results.

Implementing Sticky Components

The TestStickyPatterns.Component attached property would be defined like this:

Public Shared ReadOnly ComponentProperty As DependencyProperty = _
    DependencyProperty.RegisterAttached("Component", _
    GetType(IStickyComponent), GetType(StickyTestComponent), _
    New PropertyMetadata(AddressOf StickyComponentManager.OnStickyComponentChanged))
Public Shared Function GetComponent(ByVal d As DependencyObject) As IStickyComponent
    Return d.GetValue(ComponentProperty)
End Function
Public Shared Sub SetComponent(ByVal d As DependencyObject, _
                               ByVal value As IStickyComponent)
    d.SetValue(ComponentProperty, value)
End Sub

Notice that the property metadata refers to the shared (static in C#) method StickyComponentManager.OnStickyComponentChanged in order to enable lifecycle management for the component.

Its OnAttach and OnDetach implementations look as follows:

Public Sub OnAttach(ByVal sender As Object, ByVal e As EventArgs) Implements IStickyComponent.OnAttach
    MyBase.OnAttach(sender, e)
    If _UseCommand Then
        StickyComponentManager.Attach(sender, MyCommand, AddressOf OnExecuted, Nothing)
        StickyComponentManager.Attach(sender, New KeyGesture(Key.Space, ModifierKeys.Control), MyCommand)
    Else
        StickyComponentManager.Attach(sender, ButtonBase.ClickEvent, AddressOf OnClick)
        StickyComponentManager.Attach(sender, ButtonBase.ClickEvent, AddressOf OnClickOneShot, True)
        StickyComponentManager.Attach(sender, ButtonBase.ClickEvent, AddressOf OnClickCancel, FocusManager.LostFocusEvent)
    End If
End Sub

Public Sub OnDetach(ByVal sender As Object, ByVal e As EventArgs) Implements IStickyComponent.OnDetach
    MyBase.OnDetach(sender, e)
    If _UseCommand Then
        StickyComponentManager.Detach(sender, New KeyGesture(Key.Space, ModifierKeys.Control))
        StickyComponentManager.Detach(sender, MyCommand)
    Else
        StickyComponentManager.Detach(sender, ButtonBase.ClickEvent, AddressOf OnClick)
        StickyComponentManager.Detach(sender, ButtonBase.ClickEvent, AddressOf OnClickOneShot)
        StickyComponentManager.Detach(sender, ButtonBase.ClickEvent, AddressOf OnClickCancel)
    End If
End Sub

 

Grouping Sticky Components

Since the idea in using Sticky Components is that their behaviour is very narrow and specialized, so that they are suitable for many different contexts, there is a need to be able to group Sticky Components and attach a whole group at once to the same base element. The Sticky Component Framework contains a generic collection to help with that: StickyComponentCollection(Of T as IStickyComponent). This collection attaches and detaches its items at the right times, provides change notification, and if you implement the INamedStickyComponent interface on the collection’s items, you even can refer to the components inside the collection using string indexers in XAML. Here is an example of the use of this collection:

<Page.Resources>
    <ex:StickyTestComponentSet x:Key="test2">
        <ex:StickyTestComponent Name="Page Immediate"/>
        <ex:StickyTestComponent Name="Page OnInitialized" AttachMode="OnInitialized"/>
        <ex:StickyTestComponent Name="Page OnLoaded" AttachMode="OnLoaded"/>
    </ex:StickyTestComponentSet>

 

StickyTestComponentSet is defined by inheriting a concrete type instance of the generic collection:

Public Class StickyTestComponentSet
    Inherits StickyComponentCollection(Of StickyTestComponent)
    Implements IStickyComponent, IList

 

Notice that for some reason the Visual Studio XAML designer (Cider) will only let you add direct content to the class if you specify “Implements IList” again, even though this interface is already implemented by the base class.

The StickyComponent Example

On the Downloads page you will find the source code for the framework and an example project called StickyComponentExample. This project mainly focuses on demonstrating the different interaction techniques between StickyComponents, their usage patterns, and their life cycle. In order to trace the life cycle, a lot of debug output is written to Debug.Print, so you should run the project in the Visual Studio Debugger and follow the output in the Immediate window.

Coming Soon…

There is one special case of a Sticky Component: the Sticky ViewModel. It deserves special attention, and even though the example is already in the example solution, I’d like to cover it in a separate post.

Implementing the Sticky Command Design Pattern

November 12, 2009 2 comments

The Sticky Command design pattern is one of the patterns in WPFGlue which allow to add custom functionality to out-of-the-box WPF controls. Adding a Sticky Command to a FrameworkElement gives it a certain new behaviour, and makes this behaviour available to the element and all its child elements through a routed command, while the implementation of the element remains separate and independent of the implementation of the behaviour.

Let’s take an example. A very common need in data oriented applications is a submit command which sends the values of a group of controls to the underlying data store. This command should be disabled when the data is invalid, and it should be possible to connect it to a KeyGesture which allows to call the command by pressing a given key when entering data.

<GroupBox x:Name="CustomerGroupBox" Header="Customer"
          v:Submit.Command="{StaticResource SubmitCommand}"
          v:Submit.KeyGesture="Enter"> <!—- Content left out for clarity -->
</GroupBox>

The Sticky Command is stuck to the GroupBox by setting the Submit.Command Sticky Property. Optionally, one can add a KeyGesture which invokes the command, in this case pressing the Enter key. The SubmitCommand is just a standard RoutedCommand:

<Window.Resources>
    <RoutedCommand x:Key="SubmitCommand"/>
</Window.Resources>

By itself it doesn’t provide any functionality; it’s just kind of an identifier for the behaviour we want to add to the GroupBox.

Creating a Sticky Property

A Sticky Property is an attached property that, in addition to storing a value on the target element, does some work in its PropertyChanged handler. In our case, this work consists of creating a CommandBinding and setting it on the target element, or removing the created CommandBinding, respectively.

Public Class Submit
    Inherits DependencyObject

    Public Shared ReadOnly CommandProperty As DependencyProperty = _
            DependencyProperty.RegisterAttached("Command", _
            GetType(RoutedCommand), GetType(Submit), _
            New PropertyMetadata(AddressOf OnCommandChanged))
    Public Shared Function GetCommand(ByVal d As DependencyObject) _
            As RoutedCommand
        Return d.GetValue(CommandProperty)
    End Function
    Public Shared Sub SetCommand(ByVal d As DependencyObject, _
            ByVal value As RoutedCommand)
        d.SetValue(CommandProperty, value)
    End Sub
    Private Shared Sub OnCommandChanged(ByVal d As DependencyObject, _
        ByVal e As DependencyPropertyChangedEventArgs)
        Dim f As FrameworkElement = TryCast(d, FrameworkElement)
        If f IsNot Nothing Then
            If e.OldValue IsNot Nothing Then
                Detach(f, e.OldValue)
            End If
            If e.NewValue IsNot Nothing Then
                Attach(f, e.NewValue)
            End If
        End If
    End Sub
'...
End Class

The implementation of OnCommandChanged is quite simple: if the property already has a value, the command should be detached from the target, and if a new value is provided, this value should be attached to it. One might ask why it is necessary to provide a Detach procedure as well. Why not just leave the CommandBinding in place? If the command can be removed by changing setting the value of Submit.Command to Nothing, then the command can be attached and detached through triggers, which opens up a whole new line of uses…

Attaching and Detaching the CommandBinding

Private Shared Sub Attach(ByVal d As FrameworkElement, _
                          ByVal command As RoutedCommand)
    d.CommandBindings.Add(New SubmitCommandBinding(command))
    Dim gesture As KeyGesture = GetKeyGesture(d)
    AttachKeyGesture(d, command, gesture)
    If d.BindingGroup Is Nothing Then
        d.BindingGroup = New BindingGroup
    End If
End Sub
Private Shared Sub Detach(ByVal d As FrameworkElement, _
                          ByVal command As RoutedCommand)
    For Each b As SubmitCommandBinding In _
            d.CommandBindings.OfType(Of SubmitCommandBinding)()
        d.CommandBindings.Remove(b)
    Next
    DetachKeyGesture(d)
End Sub

The Attach procedure creates a new CommandBinding that connects the provided RoutedCommand to its implementation, and adds it to the targets CommandBindings collection.

The Detach procedure removes the CommandBinding from the collection. In order to be able to find the correct CommandBinding, Attach uses a class derived from CommandBinding, in order to use its type as marker. This way, one doesn’t have to store a reference to the created CommandBinding in order to be able to remove it later. The dummy class is a private nested class inside the Submit class:

Private Class SubmitCommandBinding
    Inherits CommandBinding
    Public Sub New(ByVal command As RoutedCommand)
        MyBase.New(command, AddressOf OnExecutedSubmit, _
                   AddressOf OnCanExecuteSubmit)
    End Sub
End Class

The Command’s Implementation

The procedures OnExecutedSubmit and OnCanExecuteSubmit handle the RoutedCommand.CanExecute and RoutedCommand.Executed events that are sent out by the CommandBinding. It is useful to separate the code specific to event handling from the code that does the actual work:

Private Shared Sub OnCanExecuteSubmit(ByVal sender As Object, _
        ByVal e As CanExecuteRoutedEventArgs)

    Dim result As Boolean = False
    Dim target As FrameworkElement = TryCast(sender, FrameworkElement)
    If target IsNot Nothing Then
        ' Separate event specific code from domain specific code...
        result = CanExecuteSubmit(target,e.Parameter)
    End If
    e.CanExecute = result
    e.Handled = True
End Sub

Public Shared Function CanExecuteSubmit(ByVal target As FrameworkElement, _
        ByVal parameter As Object) As Boolean
    Dim result As Boolean = False
    If target IsNot Nothing Then
        result = (target.BindingGroup IsNot Nothing AndAlso Not _
                  System.Windows.Controls.Validation.GetHasError(target))
    End If
    Return result
End Function

Private Shared Sub OnExecutedSubmit(ByVal sender As Object, _
                                    ByVal e As ExecutedRoutedEventArgs)
    Dim target As FrameworkElement = TryCast(sender, FrameworkElement)
    If target IsNot Nothing Then
        If CanExecuteSubmit(target, e.Parameter) Then
            ExecuteSubmit(target, e.Parameter)
        End If
        e.Handled = True
    End If
End Sub

Public Shared Sub ExecuteSubmit(ByVal target As FrameworkElement, _
        ByVal parameter As Object)
    target.BindingGroup.UpdateSources()
End Sub

Providing a KeyGesture

In order to be able to specify a KeyGesture for the command on the target, we need to create a second Sticky Property, which is able to add the KeyGesture to the target’s InputBindings collection. The method is similar to the one used with the CommandBinding itself. However, there is one point of note: We cannot be sure of the order in which the attached properties are set on the target. So, we have to make sure that CommandBinding and InputBinding are set up correctly no matter which is specified first. Since the InputBinding depends on the CommandBinding, one could say that Submit.Command is the main Sticky Property, while Submit.KeyGesture is a supporting Sticky property. The rule would then be that the Attach and Detach procedures for the main Sticky property would have to call the Attach procedures for all supporting properties in turn, while the Attach procedures of the supporting properties only attach something if the main Sticky Property has already been set.

The implementation of the KeyGesture functionality looks like this:

Public Shared ReadOnly KeyGestureProperty As DependencyProperty = _
        DependencyProperty.RegisterAttached("KeyGesture", _
                    GetType(KeyGesture), GetType(Submit), _
                    New PropertyMetadata(AddressOf OnKeyGestureChanged))
Public Shared Function GetKeyGesture(ByVal d As DependencyObject) _
        As KeyGesture
    Return d.GetValue(KeyGestureProperty)
End Function
Public Shared Sub SetKeyGesture(ByVal d As DependencyObject, _
                                ByVal value As KeyGesture)
    d.SetValue(KeyGestureProperty, value)
End Sub
Private Shared Sub OnKeyGestureChanged(ByVal d As DependencyObject, _
        ByVal e As DependencyPropertyChangedEventArgs)
    Dim f As FrameworkElement = TryCast(d, FrameworkElement)
    If f IsNot Nothing Then
        If e.OldValue IsNot Nothing Then
            DetachKeyGesture(f)
        End If
        If e.NewValue IsNot Nothing Then
            AttachKeyGesture(f, GetCommand(f), e.NewValue)
        End If
    End If
End Sub
Private Shared Sub AttachKeyGesture(ByVal d As FrameworkElement, _
                                    ByVal command As RoutedCommand, _
                                    ByVal gesture As KeyGesture)
    If command IsNot Nothing And gesture IsNot Nothing Then
        d.InputBindings.Add(New SubmitKeyBinding(command, gesture))
    End If
End Sub
Private Shared Sub DetachKeyGesture(ByVal d As FrameworkElement)
    For Each i As SubmitKeyBinding In _
            d.InputBindings.OfType(Of SubmitKeyBinding)()
        d.InputBindings.Remove(i)
    Next
End Sub

Private Class SubmitKeyBinding
    Inherits InputBinding
    Public Sub New(ByVal command As RoutedCommand, _
            ByVal gesture As KeyGesture)
        MyBase.New(command, gesture)
    End Sub
End Class

Reusability

Once we have this submit command, we can reuse it as it is, in any project, with any kind of control or data. But what about reusability of the pattern implementation itself?

The whole Submit class consists of static members, only. This has the advantage of not creating dependent object references with the command bindings, which could interfere with the garbage collection of the page on which the command is used. Unfortunately, shared members cannot be overridden, which means that it is not straight forward to create a common base class for Sticky Commands and derive new implementations from that class. However, the domain specific code and the pattern specific code are quite easy to separate into different procedures, so that it might be an option to use Item Templates or Code Snippets in order to reuse the pattern specific code.

Conclusion

The Sticky Command pattern offers a powerful and flexible way of modifying the behaviour of standard controls without changing their implementation. Because it is used through declarative syntax, it can leverage the full power of WPF style, trigger and template mechanisms. In addition to that, a new implementation of the pattern can be created from an existing one with minimal changes.

Downloads

Download a complete example project for the Submit StickyCommand here.

Download an Item Template for Sticky Commands here.

WPFGlue Navigation

November 10, 2009 1 comment

Let me explain why WPF navigation could do with a little glue:

WPFGlue is about connecting a business object model to a user interface written in WPF, or to be more precise, entirely in XAML. So, let’s imagine the business object model is already there. To take the classic example: you’d have a Customer class that has an Orders collection with a couple of Order objects in it. In the application, you’d probably want to display a list of Customers, click on one to go to a new page that displays its details, including a link to this customers orders, which displays a List of Orders page, which leads to an Order Detail page etc. So, when you navigate from one page to the next, you need two bits of information: the URL of the page you want to go to, and the object or collection that the page should display.

The Object Selection Problem

The WPF documentation suggests passing objects to pages through constructors. This is safe but very unsticky, since it requires code behind. Moreover, pages that have been instantiated as objects and have not been called through a URL will not be freed when the user navigates away, but will be stuck in memory until the application shuts down. This makes great sense, because only by staying alive itself and holding on to its references to the business objects the page can be sure that the business objects still will be there when the user navigates back to it. However, it costs memory, and keeping business objects alive is a side effect that might not be appreciated. After all, the business object thinks it is responsible for its objects and collections, and finding an object still alive while the business object model doesn’t know it any more might have unwelcome effects.

So, this problem calls for two solutions: how to pass a selected object from one page to another while still using an URL, and how to handle object references while the user navigates back and forth through the journal.

The idea for solving the first problem is to create a combination of Sticky Properties, Sticky Behaviours and a Sticky CommandBinding. The CommandBinding would handle the NavigationCommands.GoToPage command, look for an URL and an object reference in Sticky Properties on the element that originated the command, and use the NavigationService.Navigate(URI,Object) method to navigate to the next page. The Sticky Behaviours would attach themselves to the Navigating and LoadCompleted events of the NavigationService and set the DataContext of the new page to the object that would be passed forward.

The Backward Navigation Problem

The idea for solving the second problem is to have a backup storage for object references, which can be accessed by index and restored when the user navigates backwards or forwards.

The mechanism for storing custom data in the Journal is a class called CustomContentState. By deriving from this class, one can add information to the journal that will be restored automatically when the user navigates forwards or backwards. Now, if one tries to add object references to a CustomContentState implementation, one finds out that these objects need to be serializable. What CustomContentState does is that it serializes itself, stores itself in the journal in serialized form, and is deserialized before the page is displayed again.

It is understandable why this is so: By serializing the data, one avoids having lots of unresolved object references in the journal, keeping objects from being freed and creating the same kind of side effect that is created by keeping pages alive. So, what can one do?

I decided to use WeakReferences to solve this problem. The WeakReferences are stored in a dictionary with an auto-incrementing number as index. When the user navigates away from a page, the system stores the DataContext in the dictionary and saves the index to this reference in the CustomContentState, which is retained by the Journal. When the user returns to the page, the CustomContentState tries to retrieve the DataContext using the index and the WeakReference to the object. If at this point the object has already been garbage collected, the WeakReference will show this. In this case, the CustomContentState will trigger a navigation further backwards, since the data of the page obviously has expired. If the data on all the preceding pages has expired, the application will end up on the start page, which must be able to create its own DataContext anyway (if any).

However, there is one drawback to WeakReferences: they require full trust, so they will probably not work in XBAP applications. I want to research that at some stage in the future.

The Navigation Topology Problem

It’s possible to use a hyperlink and to specify the URL of the page immediately in XAML. However, doing this means that the relationships between the pages are hardcoded in the pages themselves, and the sequence of pages and their links between each other, i.e. the navigation topology of the application, are distributed throughout all the pages. This is not very maintenance friendly, and it makes it more difficult to reuse pages in other places in an application.

The first solution to this would be to avoid URLs in the pages, and instead use a global navigation menu that is defined in a central location. The WPFGlue pattern for this would be a ViewModelKit, providing classes for Menus and MenuItems that can be configured in a resource dictionary. The View for the menu would then use this definition as ViewModel, and use it to create hyperlinks or navigation buttons. These in turn would rely on URLs set on the menu items in the resource dictionary.

Categories: Navigation Tags: , ,

WPFGlue Categories

November 7, 2009 Leave a comment

I’d like to classify WPFGlue components according to what they do in the application. So far, the following categories came out:

Navigation

The WPF navigation framework is just great. Especially the journal: you get the complete forwards and backwards navigation for free, the journal remembers the user input on the page, and this works even when pages are freed in order to save memory.

However, WPF navigation stops just short of being really sticky. Selecting an object on one page and passing it forward to another page is supposed to be done through code behind, and the journal serializes objects instead of hold references to them, which is in itself a wise thing to do in order to not keep these objects from being freed, but makes it difficult to return to the same object instance if one goes back to a page. Also, I don’t like the suggestion in the WPF documentation that the navigation topology should be defined through pages referencing each other through hyperlinks. In my opinion, the pages should work stand-alone as much as possible, and there should be a central definition for the navigation topology, defining the structure of the application and mapping pages to the appropriate places in the object model.

WPFGlue supports navigation through a sticky GoToPage CommandBinding which takes an object parameter and passes it to the DataContext of the new page, a sticky Session property which can hold WeakReferences to business objects while the journal stores pointers to these references, and a ViewModelKit for defining a navigation menu.

Localization

The need for localization is immediately obvious for every programmer whose mother tongue is not English. Surprisingly, in WPF localization seems to have been added more or less as an afterthought. While Visual Studio supports localization very nicely for Windows Forms applications, getting at resources contained in satellite assemblies is not straight forward in WPF, and even something as basic as detecting the system language and making it the default culture for display and formatting in the application requires extra work. I could imagine that in the beginning the creators of WPF thought that people would just write different XAML pages for different languages, as is done in HTML, and that the need for localizing XAML only arose after the power of XAML as a programming language became more apparent, and programming elements became more predominant on XAML pages than clear text.

In the Localization category, WPFGlue comes with some sticky MarkupExtensions which make it easier to localize an application. These MarkupExtensions get their values from standard .Net localized resources, so no need for LocBAML or third party tools there. Other MarkupExtensions can be used to set WPF elements’ Language property to the CurrentCulture or CurrentUICulture.

Commanding

The commanding support in WPF is ingenious. It allows to implement some functionality once and to attach it to all the places where it is applicable, through RoutedCommands and CommandBindings. At the same time, commands decouple the traditional menu and toolbar from the application’s object model, making for great reusable code. Fabulously sticky stuff!

Commands are also the way ViewModels in the MVVM pattern expose their functionality to the user interface. The only unsticky thing about them is that CommandBindings support adding handler routines only through code, either code behind or explicitly. Also, there is no native general way of wrapping a method call into a command.

In the Commanding category, WPFGlue should support mapping commands to method calls, and also direct commands (ICommand implementations that are exposed by a ViewModel) to routed commands which can be handled centrally. There should be a way to set up a CommandSet and to connect it to a page, thus being able to define the available commands and their handlers in a central location. Also, the Commanding category contains a CommandGroup, which executes a series of commands in one go.

Validation

MVVM developers seem to avoid the validation features of WPF in favour of validation through the ViewModel or business model, exposed through the IDataErrorInfo interface. I don’t really understand why.

First of all, providing error messages to a user is not the job of a business object. The business object shouldn’t know whether it is used by an interactive user, a background service, or a batch job. In addition to that, in order to be able to provide meaningful error messages, the business object model would have to localize its error messages, and I wouldn’t want to burden my business objects with a job like that.

Second, while the business model knows what itself can do, it has no idea about what the developer of an application that reuses it may want to do. It would be perfectly justified to forbid certain legal property values because they are outside the scope of the current application. In this case, the ViewModel would have to constrain the values it allows for a certain property before it passes them on to the business object model.

So why not let the ViewModel do the job? I agree, the ViewModel is responsible. However, I wouldn’t use IDataErrorInfo, because that forces me to re-implement a lot of functionality that is already present in the WPF validation model. For example, resetting the values of an object to their pre-edit state before they are committed while still being able to provide instant validation feedback is really easy with ValidationRules and a BindingGroup, but requires a lot of effort, including ongoing maintenance effort, when done in a ViewModel specialized for a certain business model.

So, what I’d do instead is create a ViewModelKit that allows one to define a group of ValidationRules, which may or may not be dependent on validation functions in the business object model, and to allow setting these ValidationRules to a BindingGroup using a sticky property.

In addition to that, one would find workarounds for some minor problems with Validation.ErrorTemplate and ways to inform the ViewModel of validation results in the Validation category of WPFGlue.

Application Services

Application services would be things like forwarding application lifetime events to the ViewModel or providing services that are available in the operating system environment without creating a dependency from the ViewModel to the View.

Examples for this are a MessageBox that is invoked through sticky properties, a sticky StartupCommand property, a markup extension that allows to include application settings in the user interface, or context sensitive help through sticky properties.

Common Tasks

Common tasks would be jobs that recur in user interfaces, so that it makes sense to implement them in sticky ViewModels.

Examples would be a FileManager that provides support for the usual File menu commands for any type of document, a ListEditor that has commands for moving, adding and deleting items in collections implementing the standard collection interfaces, a ListPager that divides a collection into pages of a given length, and the like.

Conclusion

This is only a tentative list. The only category that will definitely survive is Common Tasks, since the others hopefully will be replaced by native support through WPF as the framework develops and the gaps between business object model and user interface vanish, so that there is no more need to fill them with glue.

Suppose You Have a Business Object Model…

November 5, 2009 Leave a comment

which can do everything you want to do with the application. So what would be the job of the UI?

The UI enables a user to interact with the model. In terms of the business model this corresponds to

  • instantiating objects or
  • finding objects that have been instantiated already,
  • accessing their properties and
  • calling their methods.

If it is the UI’s job to forward these functions to the user, it has to be able to do the following:

  • instantiate objects,
  • provide means to navigate their relationships,
  • provide means to modify their relationships,
  • keep track of object selections,
  • display and edit object’s properties,
  • provide means to call methods,
  • capture and display the result of method calls.

“Provide means” in this context means to provide a visual presentation for the action and to translate input gestures into the necessary method calls on the object model.

In addition to that, there are some tasks that mainly concern the UI, not the object model:

  • provide descriptions of itself (internationalized),
  • provide context sensitive online help,
  • translate user readable values into machine readable values and vice versa,
  • provide validation feedback.

Ok, so much for the cooperation between business model and UI layer. However, there are some services that every application needs, independent from the actual business object model. These services include

  • persistence of business objects,
  • Notifying the business model of application lifetime events, i.e. startup and shutdown,
  • persistence of application settings.

All of these functions are already present in .Net. Most of them are also available in WPF. It remains to be seen how to connect the two in the cases where the connection is not obvious.

WPFGlue Patterns

November 5, 2009 4 comments

Let’s recapitulate the design requirements for WPFGlue components:

  • You shall not duplicate functionality that is already in the WPF framework.
  • You shall not mess with WPF’s correct function, like keeping objects from being freed and the like evil practices.
  • You shall not require code behind.
  • You shall not demand sub-classing controls.
  • You shall not demand interface implementations from your business objects (unless the interfaces are part of WPF itself), nor common base classes, nor any other construct that commits the developer to a strong coupling between your glue and his code.

The following design patterns have proved suitable for development under these constraints:

Sticky Properties (a.k.a. Attached Properties)

Attached properties can be used to extend the state of any element in WPF. They can be used in XAML, and neither the framework-supplied controls nor the business object model need to know them. So, they are suitable for WPFGlue.

Built-in examples for attached properties are the Canvas.Left and Canvas.Top properties, which the WPF Canvas uses to store the positions of its child elements.

Sticky Behaviours (a.k.a. Attached Behaviours)

Attached behaviours are a special kind of attached properties that register event handlers on the elements they are attached to. The event handlers provide additional functionality to the elements which is triggered through the elements standard events, while the implementation of the event handlers is contained in the class that defines the attached property.

A built-in example for a sticky behaviour is the SpellCheck.IsEnabled property, which adds the functionality of spell checking to controls based on TextBoxBase.

Josh Smith writes about attached behaviours in this article; Attached behaviours are introduced and defined by Nikhil Kothari here.

Sticky CommandBindings

Work like sticky behaviours, with the difference that they don’t handle events, but standard routed commands. Attaching a sticky CommandBinding to a WPF FrameworkElement means that this element will be able to handle the command, without having to change the original implementation of the element. A sticky CommandBinding should add / remove the CommandBindings when the value of an attached property changes.

Pete O’Hanlon gives an almost perfect example of this pattern here. Almost perfect because he uses a class CommandBinding instead of the CommandBindings collection, but this might be justified on his case since he expects the command to be used by many elements per page.

Sticky ViewModels (a.k.a. Mini-ViewModels)

Sticky ViewModels are ViewModels that don’t wrap a business object, but attach themselves to it and expose a specialized, reusable bit of functionality through their own properties and commands. Typically, a sticky ViewModel wouldn’t be the DataContext of a FrameworkElement, but it would be attached to the element as a sticky property and use the FrameworkElement’s DataContext to find the model it is supposed to work on. Controls inside the scope of the FrameworkElement would then bind to properties of the sticky ViewModel in order to benefit from it.

Quite often jobs like this are done through converters (Converters are classes that implement the IValueConverter interface). However, I view this as converter abuse. A converter is not intended for anything but type conversions, translating data between different data types and string presentations. If the intention of the solution is rather to achieve some more complex interaction between the View and the Model, I’d recommend a sticky ViewModel instead. Usually these cases are discovered by feeling the need to pass more information into the conversion routines than is readily available…

While Mini-ViewModel seems to imply that the functionality of such a class would normally be quite limited, I could imagine whole page ViewModels using this technique.

Colin Eberhardt describes the Mini-ViewModel pattern here and gives a nice example.

ViewModelKits

A ViewModelKit would be a class or set of related classes that can be instantiated and configured as XAML resources, and then be used as ViewModels through referencing the resource.

A built-in example for a ViewModelKit would be the CollectionViewSource class, which can be used to configure views of business object collections.

Sticky Markup (a.k.a. Custom Markup Extensions)

Custom markup extensions are classes derived from System.Windows.Markup.MarkupExtension, which can be used in XAML attributes using the markup extension syntax, like {Binding value}. Writing custom markup extensions is not documented very well in the WPF documentation, and I use them sparingly. They need to be initialized in place, i.e. where they are used in XAML. This limits their “stickiness” to situations where the information they need to do their job is either very simple or can be discovered from the built-in application framework. For example, I found them useful for accessing localized resources, application settings, or the current UI language.