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;
}
}