Archive

Posts Tagged ‘MVVM’

Commanding II: Beyond Calling Methods

June 30, 2012 Leave a comment

In the last post about Commanding I described a basic technique for binding RoutedCommands to method calls in the ViewModel. Today I want to introduce some refinements which make the user experience more complete: Status messages for running commands, localizing exception messages, and how to have one status bar display the status messages of multiple commands.

The complete example code for this post is contained in the CommandingExample project which is part of the WPFGluePublished download available through the downloads page.

Status Messages

If users click a button or a menu item in order to execute a command, they expect instant feedback on whether the command is executing. If the result is not visible immediately, they will appreciate a status message somewhere in the UI which tells them that the command has been executed, and also a message that tells them when it has finished.

In order to accommodate this scenario, we will add three more properties to our Command base class:

Public Shared ReadOnly ReadyMessageProperty As DependencyProperty = DependencyProperty.Register("ReadyMessage", GetType(String), GetType(Command))
Public Property ReadyMessage As String
    Get
        Return GetValue(ReadyMessageProperty)
    End Get
    Set(ByVal value As String)
        SetValue(ReadyMessageProperty, value)
    End Set
End Property

Public Shared ReadOnly WorkingMessageProperty As DependencyProperty = DependencyProperty.Register("WorkingMessage", GetType(String), GetType(Command))
Public Property WorkingMessage As String
    Get
        Return GetValue(WorkingMessageProperty)
    End Get
    Set(ByVal value As String)
        SetValue(WorkingMessageProperty, value)
    End Set
End Property

Private Shared ReadOnly StatusPropertyKey As DependencyPropertyKey = DependencyProperty.RegisterReadOnly("Status", GetType(String), GetType(Command), New PropertyMetadata())
Public Shared ReadOnly StatusProperty As DependencyProperty = StatusPropertyKey.DependencyProperty
Public Property Status As String
    Get
        Return GetValue(StatusProperty)
    End Get
    Private Set(ByVal value As String)
        SetValue(StatusPropertyKey, value)
    End Set
End Property

 

WorkingMessage and ReadyMessage are supposed to be configured by the developer. They are the messages which are shown to the user when the command starts executing and when it is finished. Status is a readonly property. This is where the messages arrive. The idea is to set Status to the WorkingMessage before one calls the ViewModel, and to the ReadyMessage when the ViewModel method has returned.

However, simply changing the property won’t get the message displayed: data binding, notifying of changes that require a new rendering, and executing the ViewModel method all happen on the same thread, so the changed status messages will not be processed until when the ViewModel method has returned. In order to give the UI time to render the WorkingMessage, we need to use an asynchronous pattern including the Dispatcher:

Protected Overridable Sub OnExecuted(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
    Exception = Nothing
    IsRunning = True
    Status = WorkingMessage
    Dim a As Func(Of Object, Object, Exception) = AddressOf Me.DoExecute
    Dim op As System.Windows.Threading.DispatcherOperation = Me.Dispatcher.BeginInvoke(a, Windows.Threading.DispatcherPriority.Background, sender, e.Parameter)
    op.Wait()
    Dim success As Boolean = (op.Result Is Nothing)
    If success Then
        Status = ReadyMessage
    Else
        Dim ex As Exception = op.Result
        Status = ex.Message
        Exception = ex
    End If
    IsRunning = False
End Sub

Protected Overridable Function DoExecute(ByVal sender As Object, ByVal parameter As Object) As Exception
    Dim result As Exception = Nothing
    Try
        Execute(sender, parameter)
    Catch ex As Exception
        result = ex
    End Try
    Return result
End Function

 

The OnExecuted method begins with setting some properties that indicate that the command is about to execute. The status message is one of them. Then, it calls Dispatcher.Invoke with the address of a wrapper function, DoExecute, which calls the ViewModel method. The Dispatcher.Invoke call includes a DispatcherPriority.Background parameter. This tells the Dispatcher that it should finish all its usual housekeeping chores, among others displaying our status message, before it calls the DoExecute method. Dispatcher.Invoke returns a DispatcherOperation object. Using this object, we first call Wait in order to yield control to the Dispatcher. The Dispatcher will then take care of everything that is more important (again including displaying our status message), and finally call our method. When the method has returned, the Wait method will return, and the DispatcherOperation’s Result property will contain the return value of DoExecute.

Localizing Exception Messages

The main purpose of DoExecute is to catch any exceptions that might be thrown by the ViewModel method before they reach the Dispatcher, and to expose them through the Command’s Exception property. By default, in case of an exception, the Status property will return the Exception’s Message.

However, this message might not be suitable for display to the users: it might be in a language different form the UI language, or it might be formulated in a way that makes sense to developers, but not to end users who lack the necessary technical background.

So, the UI should be able to receive Exceptions and to translate them into localized messages. Since there might be important information embedded in the original exception message, there should also be a way to extract this information and to insert it into the translated message.

The idea here is to create a converter which receives an Exception, and can be configured in order to create a String message.

The converter looks like this:

Public Class ErrorMessageConverter
    Inherits Freezable
    Implements IValueConverter

    Public Sub New()
        MyBase.New()
        ErrorMessages = New ErrorMessageCollection
    End Sub

    Protected Overrides Function CreateInstanceCore() As System.Windows.Freezable
        Return New ErrorMessageConverter
    End Function

    Private Shared ReadOnly ErrorMessagesPropertyKey As DependencyPropertyKey = DependencyProperty.RegisterReadOnly("ErrorMessages", GetType(ErrorMessageCollection), GetType(ErrorMessageConverter), New PropertyMetadata())
    Public Shared ReadOnly ErrorMessagesProperty As DependencyProperty = ErrorMessagesPropertyKey.DependencyProperty
    Public Property ErrorMessages As ErrorMessageCollection
        Get
            Return GetValue(ErrorMessagesProperty)
        End Get
        Private Set(ByVal value As ErrorMessageCollection)
            SetValue(ErrorMessagesPropertyKey, value)
        End Set
    End Property

    Public Function Convert(value As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
        Dim result As String = Nothing
        If value IsNot Nothing Then
            For Each em As ErrorMessage In ErrorMessages
                result = em.GetMessage(value)
                If result IsNot Nothing Then
                    Exit For
                End If
            Next
        End If

        Return result
    End Function

    Public Function ConvertBack(value As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
        Throw New NotSupportedException
    End Function
End Class

Public Class ErrorMessage
    Inherits Freezable

    Protected Overrides Function CreateInstanceCore() As System.Windows.Freezable
        Return New ErrorMessage
    End Function

    Public Shared ReadOnly ExceptionProperty As DependencyProperty = DependencyProperty.Register("Exception", GetType(String), GetType(ErrorMessage), New PropertyMetadata("Exception"))
    Public Property Exception As String
        Get
            Return GetValue(ExceptionProperty)
        End Get
        Set(ByVal value As String)
            SetValue(ExceptionProperty, value)
        End Set
    End Property

    Private Shared ReadOnly MessageParserProperty As DependencyProperty = DependencyProperty.Register("MessageParser", GetType(System.Text.RegularExpressions.Regex), GetType(ErrorMessage))
    Private Property MessageParser As System.Text.RegularExpressions.Regex
        Get
            Return GetValue(MessageParserProperty)
        End Get
        Set(ByVal value As System.Text.RegularExpressions.Regex)
            SetValue(MessageParserProperty, value)
        End Set
    End Property

    Public Shared ReadOnly MessageRegExProperty As DependencyProperty = DependencyProperty.Register("MessageRegEx", GetType(String), GetType(ErrorMessage), New PropertyMetadata(AddressOf OnMessageRegExChanged))
    Public Property MessageRegEx As String
        Get
            Return GetValue(MessageRegExProperty)
        End Get
        Set(ByVal value As String)
            SetValue(MessageRegExProperty, value)
        End Set
    End Property
    Private Shared Sub OnMessageRegExChanged(ByVal d As ErrorMessage, ByVal e As DependencyPropertyChangedEventArgs)
        Try
            d.MessageParser = New System.Text.RegularExpressions.Regex(e.NewValue)
        Catch ex As Exception
            d.MessageParser = Nothing
        End Try
    End Sub

    Public Shared ReadOnly FormatProperty As DependencyProperty = DependencyProperty.Register("Format", GetType(String), GetType(ErrorMessage))
    Public Property Format As String
        Get
            Return GetValue(FormatProperty)
        End Get
        Set(ByVal value As String)
            SetValue(FormatProperty, value)
        End Set
    End Property

    Public Function IsMatch(ByVal ex As Exception) As Boolean
        Dim result As Boolean = ex IsNot Nothing
        If result Then
            result = ex.GetType.FullName.EndsWith(Exception)
        End If
        If result And MessageParser IsNot Nothing Then
            result = MessageParser.IsMatch(ex.Message)
        End If
        Return result
    End Function

    Public Function GetMessage(ByVal ex As Exception) As String
        Dim result As String = Nothing
        If IsMatch(ex) Then
            If MessageParser Is Nothing Then
                result = Format
            Else
                Dim m As System.Text.RegularExpressions.Match = MessageParser.Match(ex.Message)
                Dim values() As String = (From g As System.Text.RegularExpressions.Group In m.Groups
                                          Select g.Value).ToArray
                result = String.Format(Format, values)
            End If
        End If
        Return result
    End Function
End Class

Public Class ErrorMessageCollection
    Inherits FreezableCollection(Of ErrorMessage)
End Class

 

The most important element here is the ErrorMessage class. The ErrorMessage class has the following properties:

  • Exception: The type name of the Exception class, or at least the last part of it.
  • MessageRegEx: optionally, a standard .Net regular expression which must match the original exception message. It can contain grouping constructs (i.e. parentheses) in order to extract information from the exception message.
  • Format: the String into which the exception message should be translated. This string can contain format placeholders (like {1}) for the information extracted from the original exception message.
    If the converter receives an exception, it iterates the configured ErrorMessage objects in order to find the first one that matches the exception. Then it calls GetMessage on this object in order to return a message, and stops the iteration. Since the Exception property only matches the last part of the exception’s type name, can configure a catchall using Exception=”Exception” on the last ErrorMessage object in your ErrorMessageConverter.

Here an example for how to configure an ErrorMessageConverter:

<l:ErrorMessageConverter x:Key="errorMessageTranslator">
    <l:ErrorMessage Exception="InvalidOperationException"
                    MessageRegEx="This operation is ([^!]*)!" Format="Don't try {1} operations!"/>
</l:ErrorMessageConverter>

 

Notice that the regular expression’s first capture group has index 1, while index 0 will return the complete match.

Creating a Status Line

While we can now display status messages for one command, normally one doesn’t want one status control for each command that might be executed through the UI. Instead, normally there is a status line that displays status of any command that might be executing at the moment.

So, what we need is kind of a funnel which collects status messages from all commands and always returns the most recent message. The component which does this is called FunnelConverter:

Public Class FunnelConverter
    Implements IMultiValueConverter

    Private _Values() As Object
    Private _Result As Object = Nothing

    Public Function Convert(values() As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IMultiValueConverter.Convert
        Dim result As Object = Nothing

        If values Is Nothing OrElse values.Length = 0 Then
            _Values = Nothing
        Else
            Dim i As Integer = 0
            Do While _Values IsNot Nothing AndAlso (i < _Values.Length And i < values.Length And result Is Nothing)
                If _Values(i) Is Nothing OrElse Not _Values(i).Equals(values(i)) Then
                    result = values(i)
                End If
                i += 1
            Loop
            Do While result Is Nothing And i < values.Length
                result = values(i)
                i += 1
            Loop
            _Values = values.ToArray
        End If

        If result IsNot Nothing Then
            _Result = result
        End If
        Return _Result

    End Function

    Public Function ConvertBack(value As Object, targetTypes() As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object() Implements System.Windows.Data.IMultiValueConverter.ConvertBack
        Throw New NotSupportedException
    End Function

 

This class is a MultiBindingConverter. It is supposed to be used with a MultiBinding, which accepts an array of bindings, and returns a new value whenever one of the bound values changes. The FunnelConverter stores a copy of the list of values it receives, and displays the first value that has changed, or the first value which is not nothing if there are no values, yet. Since all command status changes are executed on the UI thread, only one value will change at any given time, and no changes will be lost. Since this converter stores the results of the last invocation, one has to make sure that each converter instance is only used in one binding; so, the most natural solution is to not declare the converter as a resource, but to instantiate it inline in the MultiBinding tag:

<StatusBarItem>
    <StatusBarItem.Content>
        <MultiBinding>
            <MultiBinding.Converter>
                <c:FunnelConverter/>
            </MultiBinding.Converter>
            <Binding Source="{StaticResource commands}" Path="Commands[Open].Status"/>
            <Binding Source="{StaticResource commands}" Path="Commands[Find].Status"/>
            <Binding Source="{StaticResource commands}" Path="Commands[Print].Status"/>
            <Binding Source="{StaticResource commands}" Path="Commands[Stop].Status"/>
            <Binding Source="{StaticResource commands}" Path="Commands[Print].Exception" Converter="{StaticResource errorMessageTranslator}"/>
        </MultiBinding>
    </StatusBarItem.Content>
</StatusBarItem>

Conclusion

Using the techniques described in this post, one can keep the users informed about what the application is currently doing, and about any exceptions that might occur in ViewModel code. Since all messages which are configured in XAML can be localized, using the classes described here is also a step towards globalizing the application.

Another topic I want to cover in a later post is how to have commands executed asynchronously in the background, either on a background thread or by executing a number of short operations on the Dispatcher.

Commanding: Binding Controls to Methods

May 7, 2012 Leave a comment

A Command in WPF encapsulates a method to do something, a check on whether it is possible to do it at the moment , and a notification of when that state changes. It does this in a way so that one can bind a control like a Button or MenuItem to a command, and the control will execute the command when clicked and enable and disable itself according to whether the command is available.

WPF supports this infrastructure through two APIs: CommandBindings, which can be defined in XAML, but can only call methods defined in the XAML’s code-behind file, and the ICommand-Interface, which can be implemented in ViewModel classes, and supports creating properties in the ViewModel which allow to bind a control to a command.

For the first approach, I don’t like that I have to write code in the code-behind file. Defining a command is a routine thing, so I’d like to do it in XAML.

For the second approach, I don’t like that I have to implement an interface, and create kind of standard boilerplate glue-code in order to be able to make the UI call a method in the model. If possible, I want to do all the gluing that is necessary in XAML only.

What would an ideal solution look like? I’d like to have a way to just take any normal method in the ViewModel, bind a command to it (that would be a RoutedCommand object, like with the CommandBinding approach), and assign the RoutedCommand to any Control that supports commands.

In the post about the Sticky Command Design Pattern, I have already demonstrated how one can set up CommandBindings through attached properties. Now, I want to generalize this approach into a commanding framework.

A Reusable Sticky Command

The first element is a reusable component which ties a RoutedCommand and its implementation together. Basically, it contains the same information as a CommandBinding, and in fact it is just a wrapper and adapter which is responsible for creating CommandBindings while overcoming their limitations.

So, on the one hand, the Command class defines the usual Attach and Detach methods for Sticky Components:

Protected Overrides Sub Attach(ByVal sender As Object)
    If SupportsCanExecute Or UseValidation Then
        StickyComponentManager.Attach(sender, Command, AddressOf OnExecuted, AddressOf OnCanExecute, Preview)
    Else
        StickyComponentManager.Attach(sender, Command, AddressOf OnExecuted, Nothing, Preview)
    End If
End Sub

Protected Overrides Sub Detach(ByVal sender As Object)
    StickyComponentManager.Detach(sender, Command)
End Sub

 

Command here is a property which holds a RoutedCommand and which can be configured through XAML. UseValidation and Preview are also properties which can be configured through XAML.

On the other hand, the Command class defines standard implementations for the CommandBinding’s Executed and CanExecute delegates:

Public Overridable Sub Execute(ByVal parameter As Object)

End Sub

Protected Overridable ReadOnly Property SupportsCanExecute() As Boolean
    Get
        Return False
    End Get
End Property

Public Overridable Function CanExecute(ByVal sender As Object, ByVal parameter As Object) As Boolean
    Return CanExecute(parameter)
End Function

Public Overridable Function CanExecute(ByVal parameter) As Boolean
    Return True
End Function

Private Sub OnExecuted(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
    Exception = Nothing
    Status = WorkingMessage
    Dim a As Func(Of Object, Object, Exception) = AddressOf Me.DoExecute
    Dim op As System.Windows.Threading.DispatcherOperation = Me.Dispatcher.BeginInvoke(a, Windows.Threading.DispatcherPriority.Background, sender, e.Parameter)
    op.Wait()
    Dim success As Boolean = (op.Result Is Nothing)
    If success Then
        Status = ReadyMessage
    Else
        Dim ex As Exception = op.Result
        Status = ex.Message
        Exception = ex
    End If
End Sub

Private Function DoExecute(ByVal sender As Object, ByVal parameter As Object) As Exception
    Dim result As Exception = Nothing
    Try
        Execute(sender, parameter)
    Catch ex As Exception
        result = ex
    End Try
    Return result
End Function

Private Sub OnCanExecute(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
    Try
        e.CanExecute = True
        If SupportsCanExecute Then
            e.CanExecute = CanExecute(sender, e.Parameter)
        End If
        If e.CanExecute And UseValidation Then
            e.CanExecute = Not System.Windows.Controls.Validation.GetHasError(sender)
        End If
        e.Handled = Handled
    Catch
        e.Handled = False
    End Try
End Sub

 

This code contains some details which I am going to cover in later posts. The important thing for now is: there are standard event handlers which can be attached to a CommandBinding, and their real work is done in the overridable Execute and CanExecute methods. These methods are supposed to be implemented by derived classes.

Binding to Methods

So far, we have an object which can create a CommandBinding by attaching itself to a Control. The next step is to bind a method of our ViewModel to this object.

For this purpose, I created a subclass of Command, ActionCommand, which defines a property of type Action, i.e. a Delegate for a method that doesn’t take parameters and doesn’t return a result.

Public Shared ReadOnly ExecutedActionProperty As DependencyProperty = DependencyProperty.Register("ExecutedAction", GetType(Action), GetType(ActionCommand))
Public Property ExecutedAction As Action
    Get
        Return GetValue(ExecutedActionProperty)
    End Get
    Set(ByVal value As Action)
        SetValue(ExecutedActionProperty, value)
    End Set
End Property

Public Overrides Sub Execute(ByVal sender As Object, ByVal parameter As Object)
    If ExecutedAction IsNot Nothing Then
        ExecutedAction.Invoke()
    End If
End Sub

 

The class overrides the Execute method with an implementation that invokes the method the ExecutedAction delegate is bound to.

In order to be able to bind a value to the ExecutedAction delegate, I created the property as a DependencyProperty. Also, I derived the base class for my Command from Freezable. Freezables are special objects that are optimized for use as resources. What makes them extremely useful in our case is that they inherit the DataContext of the FrameworkElement in whose Resources section they are defined. The DataContext will be our ViewModel object. So, the only thing lacking is a way to create a Delegate for one of its methods through a Binding.

The solution here is a converter. The special converter we use in this case will accept the name of the method as ConverterParameter. Then it will inspect the type of the bound property and the type of the bound object in order to create a Delegate with a matching signature.  This is its code:

Public Class ActionConverter
    Implements IValueConverter

    Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
        If value Is Nothing OrElse parameter Is Nothing OrElse Not TypeOf parameter Is String OrElse Not GetType([Delegate]).IsAssignableFrom(targetType) Then
            Return Nothing
        Else
            Return WPFGlue.Framework.StickyComponentManager.CreateActionDelegate(value, parameter, targetType)
        End If
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
        Throw New NotSupportedException()
    End Function
End Class

 

And the method which creates the Delegate:

Public Shared Function CreateActionDelegate(ByVal target As Object, ByVal methodName As String, ByVal actionType As Type) As [Delegate]
    Dim result As [Delegate] = Nothing

    If target IsNot Nothing AndAlso Not String.IsNullOrEmpty(methodName) AndAlso GetType([Delegate]).IsAssignableFrom(actionType) Then
        Dim targetType As System.Type = target.GetType
        Dim methodInfo As System.Reflection.MethodInfo
        methodInfo = targetType.GetMethod(methodName, actionType.GetGenericArguments)
        If methodInfo IsNot Nothing Then
            result = [Delegate].CreateDelegate(actionType, target, methodInfo, False)
        End If
    End If

    Return result

End Function

 

Gluing it Together in XAML

While this looks quite complex, the good news is that one needs to create this kind of class only once, and from then on can use it to bind to method in XAML only. This is how one would define a Command which binds to a method in the ViewModel:

<c:ActionCommand Command="Open" ExecutedAction="{Binding Converter={StaticResource actionConverter}, ConverterParameter=Open}"/>

 

In this case, the we use the predefined Open RoutedCommand, and bind it to a method called Open (as specified by the ConverterParameter in the Binding) on the current DataContext. Instead of the predefined Open command, we could use any RoutedCommand, even those defined in our own application.

We connect the command to a Control using a Sticky Property which the commanding framework defines:

<StackPanel c:Commanding.CommandSet="{StaticResource commands}">
    <Button Command="Open">Open</Button>

 

As you can see, the Button which triggers the command is completely unaware of its implementation: it just knows that it should work with the Open predefined command, and the rest works through the WPF RoutedCommand infrastructure. This means that you can also take advantage of command routing, like having a MenuItem triggering the same command on different controls depending on which control has keyboard focus. This is more than one gets using the traditional MVVM RelayCommand approach.

Conclusion

Even though it is a bit of work, it is possible to create reusable components which allow it to bind a RoutedCommand to a method of a ViewModel using XAML only. With this technique, it is possible to take advantage of WPF command routing, while at the same time the amount of glue code in the ViewModel is reduced.

You can find the full code and an example project, CommandingExample, in the WPFGluePublished download through the Downloads page.

In posts to come I will cover more details of the WPFGlue Commanding framework, like executing commands on background threads, displaying status and exception messages, or defining CommandSets in order to attach several commands in one line of XAML.

The Sticky ViewModel Pattern

December 16, 2009 1 comment

A Sticky ViewModel is a special type of Sticky Component which adds functionality to the ViewModel instead of to the View. By binding to the DataContext of its base element, the Sticky ViewModel is able to provide services which the ViewModel itself doesn’t include. In this respect, it is similar to the Mini-ViewModel pattern, which you might prefer if you want to provide an encapsulated reusable View for the added functionality as well.

An Example

The model or ViewModel might have a property which contains a persons name. In the View, you might want to be able to edit first name and last name separately. I have already discussed this example in the context of the Stateless Sticky ViewModel pattern, so here I want to add some extra: the new implementation should format the name either John Smith or Smith, John, depending on a boolean property LastNameFirst which one can use to configure the behaviour.

The example is contained in the StickyComponentExample project which you will find in the WPFGluePublished solution on the Downloads page.

Using a Sticky ViewModel

Like any other Sticky Component, you would initialize a Sticky ViewModel in the resources of an element that wants to use them:

<Grid.Resources>
  <ex:NameStickyViewModel x:Key="viewModel"
      LastNameFirst="True" FullName="{f:StickyBinding Name}"/>
</Grid.Resources>

Using the LastNameFirst property, we specify that we want the full name displayed in the Smith, John format.

But what is the meaning of the {f:StickyBinding } markup extension? It is understood that the Sticky ViewModel somehow accesses the DataContext of its base element in order to enhance it. In fact, there is a DataContext property in the StickyViewModel base class which is synchronized with the base’s DataContext automatically.

However, if the Sticky ViewModel would get the information it needs directly from the DataContext, it would have to know its type, thus being closely coupled to the ViewModel, which we want to avoid, since we want to be able to re-use the Sticky ViewModel wherever we need its functionality. So, the idea is to get the necessary information from the DataContext through data binding. Unfortunately, since the Sticky ViewModel is not part of the logical WPF tree, normal bindings cannot access the base element’s DataContext implicitly, like child controls. So, we use a special binding class, the StickyBinding, which allows us to bind to the DataContext of the StickyViewModel, instead. By writing FullName=”{f:StickyBinding Name}” we instruct the StickyViewModel to look for the value it should edit in the Name property of the model the element is bound to.

As usual, the Sticky ViewModel is attached to its base through an attached property:

<Grid x:Name="base"
  ex:NameStickyViewModel.ViewModel="{DynamicResource viewModel}"
      HorizontalAlignment="Stretch">

In this case, we have to refer to it with a DynamicResource extension, since it is contained in the resources of the element it is used on and thus is referred to before it is declared. We could also put it into the page’s resources and use a StaticResource extension. (StaticResource extensions are less complicated, so they are a little bit safer and faster, but they can only be specified where the definition comes before the reference in the XAML). However, in the example, the NameStickyViewModel is used in a DataTemplate for a ListView. So, every row of the ListView needs its own instance of the Sticky ViewModel, otherwise the names from different rows will start mixing. We can make sure of this either by putting the declaration of the StickyViewModel into the DataTemplate itself, as I have done here, or by setting x:Shared=”False” where we declare it, which tells WPF to create a new instance of a resource every time it is accessed.

The rest of the DataTemplate defines three TextBoxes for each row:

<TextBox Text="{Binding Name, TargetNullValue='[New Customer]'}"
         Margin="30,0,0,0"/>
<TextBox Grid.Column="1" Text="{Binding ElementName=base,
  Path=(ex:NameStickyViewModel.ViewModel).LastName}"/>
<TextBox Grid.Column="2" Text="{Binding ElementName=base,
  Path=(ex:NameStickyViewModel.ViewModel).FirstName}"/>

The first TextBox is bound directly to the DataContext of the DataTemplate. It refers to the property in the model that contains the full name of a person. The other two TextBoxes are bound to the StickyViewModel that lives on the element named “base”; this element is the Grid from above.

Implementing the Sticky ViewModel Pattern

In order to support binding on their properties, Sticky ViewModels are derived from DependencyObject and expose their working properties as DependencyProperties. Configuration properties don’t need to be data bound, so they are defined as normal properties.

Like in the Stateless Sticky ViewModel, after implementing the logic which does what the model should do, the main point is distributing the change notifications from the different properties so that the logic is called at the right time. This happens in the OnPropertyChanged method of the Sticky ViewModel, which is originally defined in DependencyObject:

Protected Overrides Sub OnPropertyChanged(ByVal e As System.Windows.DependencyPropertyChangedEventArgs)
    MyBase.OnPropertyChanged(e)
    Static changeInitiator As DependencyProperty = Nothing

    If changeInitiator Is Nothing Then
        changeInitiator = e.Property

        Select Case e.Property.Name
            Case "FullName"
                FirstName = DetermineFirstName(FullName)
                LastName = DetermineLastName(FullName)
            Case "FirstName", "LastName"
                FullName = DetermineFullName(FirstName, LastName)
        End Select

        changeInitiator = Nothing
    End If
End Sub

 

Again like in the Stateless Sticky ViewModel, we remember between invocations which property started the change and cancel subsequent invocations of the method. However, this time the code is a little bit shorter and cleaner and not distributed between different methods (I just notice that one could implement it the same way with a Stateless Sticky ViewModel, but alas… never get it perfect the first time.)

Under the Hood

The Sticky Component Framework supports the Sticky ViewModel pattern with two components: the StickyViewModel base class, which can be used to derive one’s own Sticky ViewModels, and the StickyBinding, which one needs to be able to bind to the properties of the Sticky ViewModel’s DataContext.

The StickyViewModel class mainly manages attaching and detaching the ViewModel on its base element:

Public Sub OnAttach(ByVal sender As Object, ByVal e As System.EventArgs) Implements IStickyComponent.OnAttach
    Me.DataContext = StickyComponentManager.GetDataContext(sender)
    StickyComponentManager.AttachDataContextChanged(sender, AddressOf _DataContextChanged)
    Attach(sender, e)
End Sub

Public Sub OnDetach(ByVal sender As Object, ByVal e As System.EventArgs) Implements IStickyComponent.OnDetach
    Me.DataContext = Nothing
    StickyComponentManager.DetachDataContextChanged(sender, AddressOf _DataContextChanged)
    Detach(sender, e)
End Sub

It adds a handler to the base’s DataContextChanged event, so that the DataContext stays synchronised with the base’s DataContext. DataContext is a DependencyProperty, so it provides its own change notifications. Furthermore, the class defines a generic ViewModel attached property which can be used in derived classes in order to attach the model to the element.

The StickyBindingExtension basically is a BindingExtension with a reduced set of properties (everything related to input and validation is not needed on the StickyBinding), and in principle delegates all it does to this binding:

Public Overrides Function ProvideValue(ByVal serviceProvider As System.IServiceProvider) As Object
    Dim target As System.Windows.Markup.IProvideValueTarget = serviceProvider.GetService(GetType(System.Windows.Markup.IProvideValueTarget))
    If target IsNot Nothing Then
        If TypeOf target.TargetProperty Is DependencyProperty Then
            If TypeOf target.TargetObject Is StickyViewModel Then
                Dim dataPath As String = "DataContext"
                If Not String.IsNullOrEmpty(Path) Then
                    If Path.StartsWith("/") Or Path.StartsWith("[") Then
                        dataPath &= Path
                    Else
                        dataPath &= "." & Path
                    End If
                End If
                Dim b As New Binding(dataPath)
                b.Source = target.TargetObject
                b.Mode = Mode
                b.Converter = Converter
                b.ConverterCulture = ConverterCulture
                b.ConverterParameter = ConverterParameter
                Return b.ProvideValue(serviceProvider)
            End If
        End If
    End If
    Return Me
End Function

 

The trick here is to prefix the binding’s path with the DataContext property and always use the target object as source. Thus, following the principles of WPFGlue, I avoid to implement my own version of change notification listeners and instead use what is already there. Since the DataContext is always synchronized with the the base’s DataContext and provides change notification, the StickyBinding will always be able to find the correct property without any explicit dependencies.

Notice that the last line in the block that creates the binding returns Binding.ProvideValue. This is necessary in order to mimic Binding’s behaviour in all contexts.

Comparing Stateless and Stateful Sticky ViewModel

As mentioned before, the main advantage of the Stateful Sticky ViewModel is that it bundles configuration properties in one place and forms a better defined unit than the Stateless version. Its main focus is on the base’s DataContext. Sticky Bindings don’t support binding to properties of elements in the logical tree, as it would be possible with the ElementName or RelativeSource properties of a normal binding. However, if one needs that, one can combine the two patterns and define attached properties on the Sticky ViewModel for no other purpose than to be able to bind them to logical tree elements, and access them through a reference to the base that is acquired during Attach and of course released during Detach.

Coming Soon…

The Sticky Component Framework is still once removed from a real application… the next step will be a Commanding Framework based on Sticky Components which allows to define RoutedCommands, their keyboard shortcuts and display texts in one place, delegating their invocations to methods or ICommand implementations in the ViewModel or model.

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.

Forwarding the Result of WPF Validation in MVVM

December 3, 2009 2 comments

A question that is frequently raised in connection with MVVM design is how one can access the result of WPF Validation (Validation.HasError) from the ViewModel. There is a way, but before I start explaining it, I’d like to ask an important question:

Why Would You Want to Do it?

Normally you would say: actually the ViewModel is responsible for validating the user input. So, if the input is invalid, the ViewModel should already know about it, isn’t it? Well, partially. There are some cases were the user input never reaches the ViewModel: when what the user entered cannot be converted to the correct data type, e.g. with date values or numbers. Catching these conversion errors in the ViewModel requires that you wrap each and every property of the data model that has one of these data types into a ViewModel property of type string, which bloats the ViewModel unnecessarily, and creates exactly the kind of glue code one tries to avoid by using the MVVM pattern in the first place.

One possibility to work around this is to create general, reusable ValidationRules for type checking and assign them to the Bindings. But then the ViewModel would have to know about the results of these checks in order to disable or enable commands or make other decisions based on the validity of its data. This would be the use case for the following technique:

How to Do it

The trick is to create a Sticky Property (which is a special case of an attached property) which, different from Validation.HasError, allows data bindings with direction to the source:

Public Shared ReadOnly MVVMHasErrorProperty As DependencyProperty = _
    DependencyProperty.RegisterAttached("MVVMHasError", GetType(Boolean), GetType(Window1), _
    New FrameworkPropertyMetadata(False, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, _
    Nothing, AddressOf CoerceMVVMHasError))
Public Shared Function GetMVVMHasError(ByVal d As DependencyObject) As Boolean
    Return d.GetValue(MVVMHasErrorProperty)
End Function
Public Shared Sub SetMVVMHasError(ByVal d As DependencyObject, ByVal value As Boolean)
    d.SetValue(MVVMHasErrorProperty, value)
End Sub

 

In the metadata of this property, I set a flag that tells WPF that this property expects to forward its value to the source, so we don’t have to set the Binding Mode on the bindings in XAML.

In order to reflect the value of Validation.HasError, we need to set up an event that fires whenever the value of this property changes. In order to find out that we need this event, the CoerceValue callback of the property checks whether the property is data bound:

Private Shared Function CoerceMVVMHasError(ByVal d As DependencyObject, ByVal baseValue As Object) As Object
    Dim result As Boolean = baseValue
    If BindingOperations.IsDataBound(d, MVVMHasErrorProperty) Then
        If GetHasErrorDescriptor(d) Is Nothing Then
            Dim desc As System.ComponentModel.DependencyPropertyDescriptor = System.ComponentModel.DependencyPropertyDescriptor.FromProperty(System.Windows.Controls.Validation.HasErrorProperty, d.GetType)
            desc.AddValueChanged(d, AddressOf OnHasErrorChanged)
            SetHasErrorDescriptor(d, desc)
            result = System.Windows.Controls.Validation.GetHasError(d)
        End If
    Else
        If GetHasErrorDescriptor(d) IsNot Nothing Then
            Dim desc As System.ComponentModel.DependencyPropertyDescriptor = GetHasErrorDescriptor(d)
            desc.RemoveValueChanged(d, AddressOf OnHasErrorChanged)
            SetHasErrorDescriptor(d, Nothing)
        End If
    End If
    Return result
End Function
Private Shared Sub OnHasErrorChanged(ByVal sender As Object, ByVal e As EventArgs)
    Dim d As DependencyObject = TryCast(sender, DependencyObject)
    If d IsNot Nothing Then
        d.SetValue(MVVMHasErrorProperty, d.GetValue(Validation.HasErrorProperty))
    End If
End Sub

Private Shared ReadOnly HasErrorDescriptorProperty As DependencyProperty = DependencyProperty.RegisterAttached("HasErrorDescriptor", GetType(System.ComponentModel.DependencyPropertyDescriptor), GetType(Window1))
Private Shared Function GetHasErrorDescriptor(ByVal d As DependencyObject) As System.ComponentModel.DependencyPropertyDescriptor
    Return d.GetValue(HasErrorDescriptorProperty)
End Function
Private Shared Sub SetHasErrorDescriptor(ByVal d As DependencyObject, ByVal value As System.ComponentModel.DependencyPropertyDescriptor)
    d.SetValue(HasErrorDescriptorProperty, value)
End Sub

And that’s it… Notice that the CoerceValue callback uses a private DependencyProperty in order to store the DependencyPropertyDescriptor that is used to set up the change event. This has two purposes: it allows to remove the notification conveniently, and more important, it serves as a flag in order to see whether the notification is already in place or still needs to be set up.

You can download an example for this technique here. (You will have to change the extension to .zip in order to extract the contents).

Credits

I found the information about how to monitor changes in any object’s DependencyProperties in this article by Charles Petzold.

Categories: Validation Tags: ,