Project Description

This project aims to provide a way to implement the Model View ViewModel (MVVM) architectural pattern using Plain Old CLR Objects (POCOs) while taking full advantage of .NET 4.0 DynamicObject Class.

Taking advantage of the .NET 4.0 and the DynamicObject Class, we can create a type deriving from the DynamicObject Class and specify dynamic behavior at run time. Furthermore, we can implement the INotifyPropertyChanged Interface on the derived type making it a good candidate for Data Binding.

Binding to properties

There is no difference in binding. You define the property name as below:

 <TextBox
     Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}"/>

Binding to methods

There is no difference in binding. For methods you need to bind to an ICommand Interface and since the DynamicViewModel can invoke methods on the model (with or withour args) you can use CommandBindings.

Adding CommandBindings from XAML:
 <StackPanel.CommandBindings>
     <CommandBinding
         Command="{x:Static m:ContactView.ClearNamesCommand}" />
     <CommandBinding
         Command="{x:Static m:ContactView.NavigateUriCommand}" />
 </StackPanel.CommandBindings>
Binding a button click to a method with no arguments:
 <Button
     Content="Clear Names"
     Command="{x:Static m:ContactView.ClearNamesCommand}" />
Binding a hyperlink to a method passing the an argument via CommandParameter:
<Hyperlink
    Command="{x:Static m:ContactView.NavigateUriCommand}"
    CommandParameter="http://nikosbaxevanis.com"
    NavigateUri="nikosbaxevanis.com">nikosbaxevanis.com</Hyperlink>

Wiring view commands with methods of the model

Here is how the View's DataContext is initialized properly to accept the DynamicViewModel(Of TModel) Class wrapper around the model class:

internal partial class ContactView : UserControl
{
    public static readonly RoutedCommand ClearNamesCommand  = new RoutedCommand();
    public static readonly RoutedCommand NavigateUriCommand = new RoutedCommand();
 
    public ContactView()
    {
        InitializeComponent();
 
        // Create a new instance. Once created
        // do not call methods directly on this
        // object. (Use the dynamic viewModel).
        var instance  = new ContactDetails() {
            FirstName = "Nikos",
            LastName  = "Baxevanis"
        };
 
        dynamic viewModel = new DynamicViewModel<ContactDetails>(instance);
 
        // Wire the ClearNamesCommand from the view to the viewModel.
        CommandManager.RegisterClassCommandBinding(typeof(ContactView),
            new CommandBinding(
                ClearNamesCommand,
                (sender, e) => { viewModel.ClearFullName(); },
                (sender, e) => { e.CanExecute = !String.IsNullOrWhiteSpace(viewModel.FullName); }));
 
        // Wire the NavigateUriCommand from the view to the viewModel.
        CommandManager.RegisterClassCommandBinding(typeof(ContactView),
            new CommandBinding(
                NavigateUriCommand,
                (sender, e) => { viewModel.NavigateTo(e.Parameter); },
                (sender, e) => { e.CanExecute = String.IsNullOrWhiteSpace(viewModel.FullName); }));
 
        DataContext = viewModel;
    }
}

The Model (POCO)

using System;

public sealed class Customer
{
    public String FirstName
    {
        get
        {
            return firstName;
        }

        set
        {
            firstName = value;
            SetFullName();
        }
    }

    public String LastName
    {
        get
        {
            return lastName;
        }

        set
        {
            lastName = value;
            SetFullName();
        }
    }

    public String FullName
    {
        get;
        set;
    }
}

Last edited May 22, 2012 at 3:35 PM by moodmosaic, version 33