Monday, November 23, 2009

Eventing in MVVM pattern without using Caliburn Framework

Steps:

1. You need to have an EventBehaviourFactory class. You can copy this code.


public static class EventBehaviourFactory
{
public static DependencyProperty CreateCommandExecutionEventBehaviour(RoutedEvent routedEvent, string propertyName, Type ownerType)
{
DependencyProperty property = DependencyProperty.RegisterAttached(propertyName, typeof(ICommand), ownerType,
new PropertyMetadata(null,
new ExecuteCommandOnRoutedEventBehaviour(routedEvent).PropertyChangedHandler));

return property;
}

///
/// An internal class to handle listening for an event and executing a command,
/// when a Command is assigned to a particular DependencyProperty
///

private class ExecuteCommandOnRoutedEventBehaviour : ExecuteCommandBehaviour
{
private readonly RoutedEvent _routedEvent;

public ExecuteCommandOnRoutedEventBehaviour(RoutedEvent routedEvent)
{
_routedEvent = routedEvent;
}

///
/// Handles attaching or Detaching Event handlers when a Command is assigned or unassigned
///

///
///
///
protected override void AdjustEventHandlers(DependencyObject sender, object oldValue, object newValue)
{
UIElement element = sender as UIElement;
if (element == null) { return; }

if (oldValue != null)
{
element.RemoveHandler(_routedEvent, new RoutedEventHandler(EventHandler));
}

if (newValue != null)
{
element.AddHandler(_routedEvent, new RoutedEventHandler(EventHandler));
}
}

protected void EventHandler(object sender, RoutedEventArgs e)
{
HandleEvent(sender, e);
}
}

internal abstract class ExecuteCommandBehaviour
{
protected DependencyProperty _property;
protected abstract void AdjustEventHandlers(DependencyObject sender, object oldValue, object newValue);

protected void HandleEvent(object sender, EventArgs e)
{
DependencyObject dp = sender as DependencyObject;
if (dp == null)
{
return;
}

ICommand command = dp.GetValue(_property) as ICommand;

if (command == null)
{
return;
}

if (command.CanExecute(e))
{
command.Execute(e);
}
}

///
/// Listens for a change in the DependencyProperty that we are assigned to, and
/// adjusts the EventHandlers accordingly
///

///
///
public void PropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
// the first time the property changes,
// make a note of which property we are supposed
// to be watching
if (_property == null)
{
_property = e.Property;
}

object oldValue = e.OldValue;
object newValue = e.NewValue;

AdjustEventHandlers(sender, oldValue, newValue);
}
}
}

2. Create a relay command class which inherits ICommand Interface. You can copy this code. An ICommand contains methods to execute commands. A command can be executed many times, and the parameter values can vary. This interface is mandatory on commands.

Namespace: System.Windows.Input
Assembly: PresentationCore (in PresentationCore.dll)

public class RelayCommand:ICommand
{
#region private fields
readonly Action _execute;
readonly Predicate _canExecute;
#endregion private fields

public event EventHandler CanExecuteChanged
{
add
{
if (this._canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (this._canExecute != null)
CommandManager.RequerySuggested -= value;
}

}

public RelayCommand(Action execute)
: this(execute, null)
{
}

public RelayCommand(Action execute, Predicate canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}

public void Execute(object parameter)
{
_execute(parameter);
}
}

3. Define a static class to hold a new Attached property that will attach to an object to specify to which command to execute when a particular event is raised. In this example, this is a mouse enter event in the canvas.

public static class CanvasMouseEnterBehaviours
{
public static readonly DependencyProperty MouseEnterCommand = EventBehaviourFactory.CreateCommandExecutionEventBehaviour(
Control.MouseEnterEvent,
"MouseEnterCommand",
typeof(CanvasMouseEnterBehaviours));

public static void SetMouseEnterCommand(Control o, ICommand command)
{
o.SetValue(MouseEnterCommand, command);
}

public static void GetMouseEnterCommand(Control o)
{
o.GetValue(MouseEnterCommand);
}
}

4. Create an ICommand property for Mouse Enter.
public ICommand MouseEnter
{
get
{
if (canvasMouseEnter == null)
canvasMouseEnter = new RelayCommand(param => this.CanvasMouseEnter(param));

return canvasMouseEnter;
}
}

5. Create a public method for your mouse enter event.
public void CanvasMouseEnter(object param)
{
code implementation
}

6. In your XAML, attached the behaviour of your element.






No comments:

Post a Comment

About Me

My photo
simple and straight forward