How the Presentation Model could look like when using Silverlight 2.0 (Part 3)

In my previous Part 1 and Part 2 I wrote how a Presentation Model could be implemented and how to handle Async .calls. In this post I will show you how we can avoid adding code to the Code-behind. In Part 2, I had the following code in the code-behind:

public partial class Page : UserControl
{
   private NamePresentationModel _namePresentationModel;

   public Page()
   {
      InitializeComponent();

      _namePresentationModel = new NamePresentationModel(new NameRepository());

      this.Loaded += Page_Loaded;
   }

   void Page_Loaded(object sender, RoutedEventArgs e)
   {
       LoadFromPresentationModel();
   }

   private void Button_Click(object sender, RoutedEventArgs e)
   {
     _namePresentationModel.SaveAsync((source, args) =>
                                    {
                                       messageTextBlock.Text = "NameEntity Saved";
                                    });
   }


    private void LoadFromPresentationModel()
    {
       _namePresentationModel.LoadAsync((sender, args) =>
                                     {
                                          myStackPanel.DataContext = args.Result;
                                     });
    }
}


Wouldn’t it be nice if we can leave the code-behind empty and instead specify which Presentation Model we would like to use in the XAML file instead? Here is my new code-bind:

public partial class Page : View
{
    public Page()
    {
        InitializeComponent();
    }
}


I have moved all the actions and creation of the Presentation Model to the XAML file instead:

<e:View x:Class="PresentationModelExample1.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:e="clr-namespace:Silverlight.Extension;assembly=Silverlight.Extension"
    xmlns:m="clr-namespace:PresentationModelExample1.Model;assembly=PresentationModelExample1"
    Width="400" Height="300"
    e:Action.Loaded="Load">
    <e:View.Model>
        <m:NamePresentationModel/>
    </e:View.Model>

    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel Margin="50">

            <TextBox x:Name="name" Margin="4" Text="{Binding Name}"></TextBox>

            <Button e:Action.Click="Save" Margin="10" Content="Save"></Button>

        </StackPanel>
        
    </Grid>
</e:View>


By using the Action.<EventName> Attached Property, I can specify a method located in the Presentation Model and invoke it when the <EventName> is trigged. The View.Model Attached Property is used to specify which Presentation Model the View should use. Here is the code for the View class used instead of the UserControl:

public class View : UserControl
{
    public object Model
    {
        get { return DataContext as Model; }
        set { DataContext = value; }
    }
}


As you can see when I give the Model a value, the value will be bound to the DataContext of the UserControl. I need to change the code-behind to inherits from my View class, and I also need to add a namespace to the XAML file to point out where the View class is located. Then I replace the <UserControl> element with my new View element instead. When this is done I can use normal data binding to get values from my Presentation Model. The next thing to do is to create a Attached Property to make sure they invoke the specified Presentation Model methods when an event is trigged. It’s quite easy to add a Attached Property, the following example is the Action.Click attached property:

public static class Action
{

       public static readonly DependencyProperty ClickProperty =
          DependencyProperty.RegisterAttached(
             "Click",
             typeof(string),
             typeof(Action),
             new PropertyMetadata(
                 null,
                 new PropertyChangedCallback(OnClickChanged)));


       public static string GetClick(DependencyObject element)
       {
           return (string)element.GetValue(ClickProperty);
       }


       public static void SetClick(DependencyObject element, string value)
       {
           element.SetValue(ClickProperty, value);
       }


       private static void OnClickChanged(DependencyObject sourceElement,
                                          DependencyPropertyChangedEventArgs e)
       {
           var button = sourceElement as Button;

           if (button == null)
               throw new ArgumentException("DependencyObject is not of type Button");

           button.Click += ((sender, args) => { ActionHelper.GenerateActionCall(e.NewValue.ToString(), button); });
       }
}


We only need to create a static class and then add a DependencyProperty and use the DependencyProeprty’s RegisterAttached method to register a Attached Property. The argument are the name of the Property to use, the type, owner and then a PropertyChangedCallback which will be executed when the properties value are changed. Next step is to add a Get<PropertyName> and a Set<PropertyName> method and make sure it will set and get the value from the specified DependencyProperty. The name after the Get and Set prefix is the name of the property that you want to use. So if you name the Get method to GetMyPropery, the Attached property in the XAML will be Action.GetMyProperty.

In the specified callback method of the DependencyProperty, I have hooked up to the button control’s Click event. The ActionHelper class something that I have created to help me create a method which will invoke the specified action method. So the method will only get the Model from the DataContext of the specified control and then call the InvokeMember of the model’s type, something like this:

model.GetType().InvokeMember(
                    actionName,
                    System.Reflection.BindingFlags.InvokeMethod,
                    null,
                    model,
                    arguments);


I have also added some code to map arguments of the action method to controls on the UI, so if I have a Save method with an argument called name I will get the value from a control with the same name as the argument. If the argument of the Action method is an entity, I will create a new instance of  the Entity and map it’s property to controls with the same name.

public void Save(string name)
{
    //...
}

public void Save(NameEntity name)
{
    //...
    _nameRepository.SaveName(name);
}


There are several of frameworks created to map a Presentation Model to a View without using a code-behind. I only created my own to learn more about how to extend Silverlight elements etc. You can for example get a similar framework from Nikhil (Member of the ASP.Net team) called Silverlight.FX, another project with similar functionality is the Caliburn.

Published Sunday, February 22, 2009 2:15 PM by Fredrik N

Comments

# re: How the Presentation Model could look like when using Silverlight 2.0 (Part 3)

Sunday, February 22, 2009 12:16 PM by Ed McPadden

Another Great Post...thanks!  I am just trying to learn more about Silverlight and PM (or MVVM).  I really like the attached property solution here.  It helps me further wrap my head around attached properties.

# Interesting Finds: February 22, 2009

Sunday, February 22, 2009 1:04 PM by Jason Haley

# Silverlight Cream for February 23, 2009 -- #526

Monday, February 23, 2009 7:28 PM by Community Blogs

In this issue: Fredrik Normén(2), Timmy Kokke, Shemesh, Manish Dalal, Terence Tsang, Michael S. Scherotter

# Silverlight Cream for February 23, 2009 -- #526

Monday, February 23, 2009 7:58 PM by Community Blogs

In this issue: Fredrik Normén(2), Timmy Kokke, Shemesh, Manish Dalal, Terence Tsang, Michael S. Scherotter

# re: How the Presentation Model could look like when using Silverlight 2.0 (Part 3)

Tuesday, February 24, 2009 6:04 AM by David Roh

Very nice work Fredrik.

Making the source available would be very helpful.

Thank you for sharing your hard work.

David Roh

# re: How the Presentation Model could look like when using Silverlight 2.0 (Part 3)

Tuesday, February 24, 2009 8:04 AM by Julian Dominguez

Nice post Fredrik, straight to the point.

To add another library that handles these challenges to the list, you can also use commanding from prism (which v2 now supports silverlight) and leverage the ICommand interface that is also in WPF (though in SL there is no default implementation yet, that's why Prism created attached behaviors for it).

Also, you can avoid creating the View base class by setting the model directly in the DataContext from XAML.

Links:

- Prism: www.microsoft.com/composite

- Commanding in Prism: msdn.microsoft.com/.../dd458928.aspx

- Presentation Model in Prism: msdn.microsoft.com/.../dd458863.aspx

# re: How the Presentation Model could look like when using Silverlight 2.0 (Part 3)

Tuesday, February 24, 2009 9:14 AM by Fredrik N

@Julian:

Thanks,

I have done some changes so there is no need to use replace the UserControl to a custom class any more..

I only creating this framework for fun and to have some programming tasks ;)

Leave a Comment

(required) 
(required) 
(optional)
(required)