Commands with Attached Behavior for Silverlight 3 DataForm

Some weeks ago, due to yet another question from the Composite WPF & Silverlight Codeplex forums, I found myself researching about the Silverlight 3 DataForm control. I turned to this video which allowed me to understand the basics of how it worked really fast.

The user wanted to execute a command in his view model when an item of the DataForm had been edited.

This post will not focus on explaining what this control allows (for this I really recommend the video), but focus on the implementation required instead.

Attached Behavior Saves the Day

So I checked the documentation and asked Julian Dominguez (the attached behavior guy), and Matias Woloski (an expert in the client development field) if attached behaviors was the way to go. And of course they all pointed my in that direction.

I took the Click class used in Prism-v2 and turned it into the ItemEditEnded class:

public static class ItemEditEnded
   {
       private static readonly DependencyProperty ItemEditEndedCommandBehaviorProperty
           = DependencyProperty.RegisterAttached(
           "ItemEditEndedCommandBehavior",
           typeof(DataFormItemEditEndedCommandBehavior),
           typeof(ItemEditEnded),
           null);

       public static readonly DependencyProperty CommandProperty
           = DependencyProperty.RegisterAttached(
           "Command",
           typeof(ICommand),
           typeof(ItemEditEnded),
           new PropertyMetadata(OnSetCommandCallback));

       public static readonly DependencyProperty CommandParameterProperty
           = DependencyProperty.RegisterAttached(
          "CommandParameter",
          typeof(object),
          typeof(ItemEditEnded),
          new PropertyMetadata(OnSetCommandParameterCallback));

       public static ICommand GetCommand(DataForm dataForm)
       {
           return dataForm.GetValue(CommandProperty) as ICommand;
       }

       public static void SetCommandParameter(DataForm dataForm, object parameter)
       {
           dataForm.SetValue(CommandParameterProperty, parameter);
       }

       public static object GetCommandParameter(DataForm dataForm)
       {
           return dataForm.GetValue(CommandParameterProperty);
       }

       private static void OnSetCommandCallback
           (DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
       {
           DataForm dataForm = dependencyObject as DataForm;
           if (dataForm != null)
           {
               DataFormItemEditEndedCommandBehavior behavior = GetOrCreateBehavior(dataForm);
               behavior.Command = e.NewValue as ICommand;
           }
       }

       private static void OnSetCommandParameterCallback
           (DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
       {
           DataForm dataForm = dependencyObject as DataForm;
           if (dataForm != null)
           {
               DataFormItemEditEndedCommandBehavior behavior = GetOrCreateBehavior(dataForm);
               behavior.CommandParameter = e.NewValue;
           }
       }

       private static DataFormItemEditEndedCommandBehavior GetOrCreateBehavior(DataForm dataForm)
       {
           DataFormItemEditEndedCommandBehavior behavior =
               dataForm.GetValue(ItemEditEndedCommandBehaviorProperty) as DataFormItemEditEndedCommandBehavior;
           if (behavior == null)
           {
               behavior = new DataFormItemEditEndedCommandBehavior(dataForm);
               dataForm.SetValue(ItemEditEndedCommandBehaviorProperty, behavior);
           }
           return behavior;
       }
   }

Then I created the class that would hook the DataForm’s event to the command DataFormItemEditEndedCommandBehavior:

public class DataFormItemEditEndedCommandBehavior : CommandBehaviorBase<DataForm>
    {
        public DataFormItemEditEndedCommandBehavior(DataForm dataForm)
            : base(dataForm)
        {
            dataForm.ItemEditEnded += OnItemEditEnded;
        }

        private void OnItemEditEnded(object sender, DataFormItemEditEndedEventArgs e)
        {
            ExecuteCommand();
        }
    }

As Julian explained: The first class is the one needed to create the attached behavior when the Xaml parser creates the UserControl. His blog post, ICommand for Silverlight with Attached Behaviors, uses a similar approach to the code that end up in the CAL (although it is not exactly the same), and explains how the Attached Behavior pattern works.

Putting things to work

Now I had to test that this worked correctly. With that in mind, I took the HelloWorld Quickstart and turned it into a little application with a DataForm inside its only view. To test the scenario, the command would add a new item to a list of customers which was databound to the DataForm, thus giving it an extra “page”.

You can download the code from here. Since this was originally the HelloWorld Quickstart from Prism-v2, I made some minor changes to it to make the application easier to understand.

Disclaimer: This code is provided "AS IS" with no warranties, and confers no rights.

I hope you can find good use to this.