Geeks With Blogs
Peter Tweed Exploring and explaining the mysteries of .NET

I am a keen believer when building applications in having a clean logical architecture with separation of concerns as much as possible – taking into account the goals of the project and the environment in which the application will be maintained.  As such, when it makes sense I believe in use of MVC, MVP, MVVM etc type patterns to enable efficient development and maintenance of applications.  I can testify to the worth of adopting these styles to improve the quality of products developed from my experience as developer, enterprise architect and program manager in both IT and in product development.

So when I got into  I was interested in how to adopt such a pattern for my apps.  My friend Ward Bell pointed me in the direction of blogs such this one by Nikhil Kothari to introduce me to attached behaviors.  I was looking at this last year when working with Ward on a demo application and used attached behaviors as a very powerful tool to be able to separate my client side development efforts into an MVVM pattern.  This was before the Composite Application Guidance was available (released February 2009), which would have been considered if it had been around.  I believe attached behaviors are EXTREMELY VALUABLE on their own and can be used as a valuable stepping stone to understanding separation of concern design patterns and implementing cleaner logical designs.

Attached behaviors are developed by using attached properties.  I won’t explain about attached properties or how to define them as I believe other sources (such as this and this) give great descriptions of what attached properties are and how they are defined and used. 

In this post I will show how you can use an attached property to implement an attached behavior and how to implement a MVVM pattern in Silverlight.

The sitation and problem:

-          You can develop applications that take advantage of the data binding capability in Silverlight (see my earlier post on the topic) where a class can be used as the data context for a control and it’s child controls can bind to the data properties of the class

-          The event handlers for the controls – e.g. click for button, text changed for text box – still reside in the code behind for the controls defined in the XAML and so are tightly coupled with the UI

The goal:

-          I want to be able to have the event handling functions reside in the separate class that is bound to the XAML controls and declaratively bind the event handlers to the XAML controls

-          I want zero code in the XAML code behind that relates to the handling of the events from the controls in the XAML

So to demonstrate this we’ll do the following:

a)      Start with an existing application that can be downloaded here. We'll review it before we begin.

b)      Add the infrastructure pieces that are needed to facilitate the MVVM pattern

c)      Re-factor the code we started with

d)     See the application in action

This app is built on , , and the using .

The finished code for this post can be found here.

Steps:

1.       Open the solution for the code found here.

2.       Review the code for Page.xaml and its code behind and the code for ViewModel.cs.  A ViewModel object is instantiated as a static resource for the Page User Control.  The ViewModel object has two string properties TextProperty and CopiedTextProperty that are both bound to text blocks to display their values.  When the user clicks the Copy Text button, the buttons event handler calls a function on the ViewModel resource to copy the value in the TextProperty to the CopiedTextProperty.  As the ViewModel implements INotifyProprtyChanged and the CopiedTextProperty is bound to a text block in the Page user control the text block display is automatically updated – the joy of data binding in Silverlight!

3.       Run the app and check that it’s working

OK so my goal is to have the click event be handled directly by a function in the ViewModel class that can declaratively be associated with the button in the Page.xaml file, with zero wire up code in the Page.xaml.cs file.  To do that we need a few infrastructure pieces.  We will add these now and I will explain what each does at each step.

4.       To have a function be passed around in C# we need to declare a delegate or Action<…> to refer to it.  We want to have an object that can hold that function reference so we can refer to it easily without needing a reference to the object in which the function resides.  This is effectively commanding.  In Silverlight 2.0 the ICommand interface is provided for us but prior to Silverlight 2.0 we had to define our own commanding interface.  Add a class to the Silverlight project named DelegateCommand and implement the ICommand interface.

5.       Add the following to the DelegateCommand class to declare the member variable to hold the delegate and provide a constructor with the delegate as a parameter

        private Action<object> handler;

 

        public DelegateCommand(Action<object> functionDelegate)

        {

            handler = functionDelegate;

        }

 

6.       Add the following line to the Execute function in DelegateCommand to execute the delegate. 

            handler.Invoke(parameter);

 

7.       Add a class file called ICommandProvider to the Silverlight project change the class to an interface.

8.       Add the following definition to the ICommandProvider interface

        ICommand GetCommand(string key);

 

9.       Add the following line to the top of the ViewModal.cs file

using System.Collections.Generic;

 

10.   Replace the existing ViewModel constructor with the following code

        private Dictionary<string, ICommand> commandDictionary = new Dictionary<string, ICommand>();

 

        public ViewModel()

        {

            commandDictionary.Add("GetTextButtonClick", new DelegateCommand(GetTextButtonClick) );

        }

 

        public void GetTextButtonClick(object parameter)

        {

            this.CopyText();

        }

 

This code adds a member variable Dictionary to hold references to the DelegateCommands for this view model that will be declaratively associated with XAML controls.  We are only going to have one delegate but I thought I’d include this code as a nice to have.

The constructor then adds a commandDictionary entry with a known key and a DeleteCommand object referencing the GetTextButtonClick function declared after the constructor.

11.    Change the ViewModel class to implement the ICommandProvider interface

12.   Replace the contents of the GetCommand function in the ViewModel class with the following line

        return commandDictionary[key] ?? new DelegateCommand( (o)=> {});

 

This line returns the delegateCommand object in our commandDictionary refered to by the provided key if it exists or an empty delegate that does nothing if the key cannot be found in the dictionary.

13.   Build and run the application.  HEY HOLD ON!  We haven’t decoupled the XAML code behind button click event handler.  That’s right – we have put in the infrastructure that is needed to be able to develop the attached behavior.  Now we have the infrastructure in place we can develop and use our attached behavior.

14.   Add a class called ClickBehavior to the Silverlight project and make the class static (this is part of the way attached properties are declared)

15.   Add the following code to the ClickBehavior class

        public static DependencyProperty ClickCommandProperty =

    DependencyProperty.RegisterAttached("ClickCommand", typeof(string),

        typeof(ClickBehavior),

        new PropertyMetadata(new PropertyChangedCallback(ClickCommandChanged)));

 

        public static void SetClickCommand(DependencyObject sender, string command)

        {

            sender.SetValue(ClickCommandProperty, command);

        }

 

        public static void ClickCommandChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)

        {

           

        }

 

The first line of code registers the ClickCommand attached property, the first function provides the setter function for the attached property and the second function provides the event handler for when the value of the attached property changes.

 

We will add logic to the ClickCommandChanged event handler to hook up the ViewModel delegate to the click event of the button this attached property will be assigned to.

 

16.   Add the following code to the ClickCommandChanged event handler

            Button button = sender as Button;

 

            if (button != null)

            {

                if (e.NewValue != null && e.OldValue == null)

                    button.Click += new RoutedEventHandler(uiButton_Click);

                else if (e.NewValue == null && e.OldValue != null)

                    button.Click -= new RoutedEventHandler(uiButton_Click);

            }

 

This code takes the reference for the sender (which is the XAML control that the attached property is assigned to) and checks it is a button. When assigning a value to the ClickCommand attached property we are adding an event handler to the buttons click event.  We will add that event handler next.

 

17.   Add the following code below the ClickCommandChanged event handler

        static void uiButton_Click(object sender, RoutedEventArgs e)

        {

            Button button = (Button)sender;

            string commandKey = (string)button.GetValue(ClickBehavior.ClickCommandProperty);

 

            ICommandProvider provider = null;

            DependencyObject  element = button as DependencyObject;

            while (element != null)

            {

                FrameworkElement fe = element as FrameworkElement;

                if (fe != null)

                {

                    object result = fe.Resources["ViewModel"];

                    if (result != null)

                    {

                        provider = result as ICommandProvider;

                        break;

                    }

                }

                element = VisualTreeHelper.GetParent(element);

            }

 

            if (provider != null)

            {

                ICommand command = provider.GetCommand(commandKey);

                command.Execute(sender);

            }

        }

 

This event handler retrieves the command name – the value assigned to the ClickCommand attached property, finds the ViewModel object in the visual tree, calls the GetCommand function on the ViewModel object and then calls the Execute function on the DelegateCommand that is returned.  This is where the magic happens!!!!!  The last thing to do is use the attached property to associate the button with the ViewModel GetTextButtonClick command.

 

18.   Build the application

19.   Replace the click attribute with the following attached property attribute on the button control in Page.xaml

myProj:ClickBehavior.ClickCommand="GetTextButtonClick"

 

20.   Delete the Button_Click event handler in the  Page.xaml.cs file

21.   Place a break point in the GetTextButtonClick function in ViewModel.cs and run the application

22.   Enter some text and click the Copy Text button.

23.   The breakpoint will be hit in the GetTextButtonClick function in ViewModel.cs.  If you let it run the application will complete with the same result (the text being copied) as when we used the code behind in the Page.xaml.cs file.

 

CONGRATULATIONS! You have an MVVM architecture application with separated View and View Model.

 

What have we done?

Added infrastructure to enable the Commanding pattern to be used to wrap a delegate function

Defined an attached property to handle the assigning of a named command (a delegate function) with the click event of a button control

 

Why do this?

Some reading this post would say – WHY ON EARTH WOULD I WANT TO DO ALL THIS TO MOVE THE CODE FOR A SIMPLE BUTTON CLICK?????!!!!!!!!

Because by implementing the commanding mechanism and an attached behavior like this, it’s available for re-use and is hooked up just by declaration in XAML

 

As your app development effort scales and you re-use these – you have a true separation of concerns for your development efforts and gain great quality efficiencies.

 

Your UI can be developed completely separately from your logic in the view model.  Your view model can be tested without UI being developed; i.e. it enables Test Driven Development and/or distributed Teams working synchronously on separate business functions/components with less stepping on each other’s toes or designers wrecking the use of the view when it’s already had event handlers developed and hooked up via code behind.

 

Other than the declaring the view model event handler (which you would have to do in the user control code behind anyway), adding a DelegateCommand object to the commandDictionary in the view model and assigning the command key to the ClickCommand attached property on whatever button you want (which you would have to declare the click handler attribute in XAML anyway), you don’t need any more code to scale out the use of this technique.

 

 

Many other attached behaviors can be written for any other standard control events (MouseEnter, MouseLeave, SelectionChanged, TextChanged, KeyDown, etc…..) to enable the moving of the event handler to the view model. 

 

Using attached behaviors enables a cleaner logical design and software development experience in my opinion and allows people with less architecture experience to understand and use such a pattern, rather than introducing them into using the Composite Application Guidance and many more design concepts, which they may not e ready to adopt or have no need of due to the simplicity of the application they may be developing.  Once they are used to this stepping stone, use of the CAG for complex composite apps is much more achievable for a team that hasn’t used it – if they want to adopt it.

 

Posted on Tuesday, July 7, 2009 6:58 PM Silverlight | Back to top


Comments on this post: MVVM via attached behaviors in Silverlight

# re: MVVM via attached behaviors in Silverlight
Requesting Gravatar...
This was very helpful to me, thanks!
Left by Joshua on Apr 23, 2010 11:48 AM

# re: MVVM via attached behaviors in Silverlight
Requesting Gravatar...
Agree wholeheartedly. We taken a slightly different approach and implemented behaviors as used by Blend. They offer the same encapsulation and effect the same separation but can also be implemented to appear in Blend and be applied by the designers using drag-and-drop rather than markup. We've create several different classes for menu clicks, button clicks hyperlink clicks, list box actions, etc.

The effect relies, like yours, on an implementation of the DelegateCommand which can be declared by ViewModels and referenced by name from Xaml. Works great.
Left by Bill Seddon on May 23, 2010 5:56 PM

# re: MVVM via attached behaviors in Silverlight
Requesting Gravatar...
Great approach Bill. To be able to apply using Blend is a very nice touch!
Left by Peter on May 23, 2010 9:50 PM

# re: MVVM via attached behaviors in Silverlight
Requesting Gravatar...
Hi,

http://www.creativetweed.com/blogging/files/SLAttachedProperties-StartingPoint.zip link is not active I guess. Where can I download the starting project?

Thanks
Left by Murat on Aug 13, 2012 12:52 AM

# re: MVVM via attached behaviors in Silverlight
Requesting Gravatar...
In later versions of Silverlight (4, 5) there is full support for Commands, so you dont need all those attached behaviors to archive this.

You do however, need to implement attached behavior in case when a command dependency property is not available on a control (For example, double clicking on a datagrid row).

Instead of doing "Click" attached behavior, it is better to do "Command" attached behavior.
Left by Uri on May 24, 2013 1:59 PM

Your comment:
 (will show your gravatar)


Copyright © PeterTweed | Powered by: GeeksWithBlogs.net