다음을 통해 공유


WPF: Uneventful MVVM

There’s an inevitable question crops up whilst coaching someone from a winforms or vb6 background:

“How do I do my events then?”

 Read this before that grouchy team lead coaches you.

The rumours are true.


Audience

This article is aimed at the developer who is familiar with the concept but new to using MVVM.  If you’re looking for a practical explanation of some of your options – read on.

Others articles have covered a subset of this subject, with less broad coverage or no real explanation of why you use what.  

Why Are Practical Reasons So Important?

If you don’t really understand why you should do something, it’s difficult to see why you should “buy in”. 

Without an explanation of which is most useful for what then the newbie is faced with a bewildering long list of techniques which are all new to them.

The latter is particularly “dangerous” since people tend to fall back on what they know when confused and before you know it there are event handlers all over your code.

Sample

You can see the code in this article in a sample which can be downloaded here

That sample is a rather strange piece of code because it's pretty much just a collection of coding techniques.  As presented, the sample will display messages as you trigger the commands.   You might want to comment some of these out temporarily since it's all too easy to mouse over a different control than you're examining.
You can also ( obviously ) put break points in and explore behaviour.

No Event Handlers

OK, maybe that should be “Almost No Event Handlers” but some people are very attached to their events and will try and stretch “sometimes” into “every time”.  There is almost always another, better, way.

Some event handlers are unavoidable, or there is no point in avoiding them.   As a sort of litmus test - if an event handler is going to somehow communicate with anything outside the View you should try and find a way to avoid this.

Should your event only change something in the View then it’s arguably rather more acceptable.

Why Avoid Event Handlers?

This isn’t just some academic exercise – there are strong practical reasons.

Separation of Concerns

MVVM is all about separation of concerns. With a particular interpretation on what the UI layer – the View is supposed to “do” in terms of logic. 

Passive

MVVM is a passive view pattern.  Passive doesn’t mean it does nothing at all - passive means no logic acting. The View takes no decisions and just does what it’s told.  The View should implement no logic.

Loose Coupling

The View and ViewModel are connected together very loosely by Binding.  The Binding mechanism uses weak references between the various bits of the layers.  Binding also fails gracefully.  You can instantiate a view with no viewmodel and it’ll still work.  Provide the viewmodel and the bindings will then latch on and data appears.  This is extremely robust.

Flexibility

Separation of concerns ought to make it easier to develop, maintain and refactor.  There almost always comes a point in a system’s life cycle when you need to change a fair bit of it.  The business world demands flexible applications.

Changing a piece in one layer is way easier if it’s only loosely coupled to any other layer.  The firmer the shackles between the two then the harder that change is going to be.  If those layers are all in one then they’re not so much shackled as welded together – code behind is harder to refactor than code which is in a separate loosely coupled class.

Everyone has head separation of concerns is good, but it's long term and a bit nebulous for some tastes

Until you’ve seen it in action it’s quite difficult to appreciate the benefits of separation of concerns.  Since that involves maintaining and refactoring mature systems that’s often some distance in the future for the new WPF developer.

Separation for Testing

Testing is a particular and immediate requirement which particularly requires separation of concerns for entirely practical reasons.

If you will want to test logic you want that out of code behind and somewhere else you can instantiate readily – usually meaning in the ViewModel.

Testing is so important that it’s worth explaining that as a major subject itself.

Automated Testing

The separation of concerns allows you to instantiate a viewmodel and exercise tests on it using your test runner. In a real business world TDD orientated project a developer will often be running thousands of such tests every 5 or 10 minutes.  Each of these tests needs to run very quickly.  They’re also known as “fast tests” for this reason and to distinguish from Continuous Integration based overnight “Slow Tests”.  Let’s gloss over slow tests rather than digress though. 

Automated tests are exercised using plain method calls on the class’ methods.  Tests will be in a different project and hence wouldn’t be able to test private methods.

That access modifier is a problem if you try and test views because a handler like a button click is private.  Making such a handler public is breaking encapsulation and would usually be considered bad practice.  An approach which routinely required you to break encapsulation is not a great plan.

Let’s say you went with this though.

The next problem you hit is speed.  Hauling a WPF view into memory will take a second or two each ( at best ).  A second or two doesn’t sound like a huge amount of time until you remember that this is per test. When you have thousands of these to run even half a second each would be far too slow. 

Breaking out an interface is problematic because the code you want to test lives in that view and is dependent on things in the view.  You could mock those parts of a view each depends on.  Break out more interfaces,  That’s tricky since they can be quite complicated. Each test would take longer to design and write and will therefore itself be more error prone.  
By the time you do that you usually end up with a lot of mocks and very little code tested.

There’s another problem in even justifying that work.  With MVVM you want to be testing code in that ViewModel anyway.  The ViewModel is all about separating code out from the view in the first place so that’s where you want such code, if you can possibly help it.

Summary on Testing

The bottom line is that it is impractical to fast test logic which you put in code behind. The more code you put into code behind the lower your test code coverage will be.

The lower test coverage you have, the less point there is to automated testing and the more excited those management types tend to get.

Simple Methods

Let’s start with some of the simpler approaches you will be using.

Before we start wave goodbye to your old friend event, say hello to your new best friend – Binding.

Binding is the WPF way.

Change of Variable

Many events are actually about a value change of a variable.  This will usually be a Dependency Property in WPF which means you can bind it to a public property in a ViewModel.  Make that property a propfull and you can put a method call in the setter.  Your method will be called whenever your property in the View changes.  This approach is pretty similar to an event handler so you should be starting to feel at home already.

As an example, here's a TextBox markup:

<TextBox Text="{Binding TbText, UpdateSourceTrigger=PropertyChanged}" Width="120"/>

The target of  that binding is the Text property of the TextBox in the view,  The source of the Binding is a public property in the ViewModel - TbText: 

class MainWindowViewModel: ViewModelBase
{
    private string  tbText = "OverType me";
 
    public string  TbText
    {
        get
        {
            return tbText;
        }
        set
        {
            tbText = value;
            DoSomethingWhenTextChanges();
            RaisePropertyChanged();
        }
    }
 
    private void  DoSomethingWhenTextChanges()
    {
        // Some logic about the text changing.
    }

As the name suggests, that UpdateSourceTrigger=PropertyChanged makes the binding set it's Source every time the user types a letter.
In turn the setter of that propfull will be hit and DoSomethingWhenTextChanges() when be invoked.
Here you can see the equivalent to a TextChanged handler.

Select From List / IndexChanged

If you want to do something when the user chooses an entry in a listbox or combo then this is a sort of special case of variable change.

What you do is bind selecteditem to an instance of the object the list is bound to.

As the user selects then that setter will be hit and again you can use a method called there to do whatever processing you have in mind.

Here's a piece of markup for a combobox presenting a list of Chefs:

<ComboBox ItemsSource="{Binding Chefs}"
          DisplayMemberPath="FullName"
          SelectedItem="{Binding SelectedChef}"/>

As you can see that's bound to a collection (of people ) called Chefs and the SelectedItem is bound to SelectedChef.
There's rather more code in the ViewModel:

private Person selectedChef;
 
public Person SelectedChef
{
    get
    {
        return selectedChef;
    }
    set
    {
        selectedChef = value;
        RaisePropertyChanged();
        DoSomethingWhenChefChanged();
    }
}
 
private void  DoSomethingWhenChefChanged()
{
    // Some code which is to run as selection is changed on the chefs
}
 
 
private ObservableCollection<Person> chefs = new ObservableCollection<Person>
{
 
    new Person{FirstName="Heston", LastName="Blumenthal"},
    new Person{FirstName="Keith", LastName="Floyd"},
    new Person{FirstName="Hugh", LastName="Fearnley-Whittingstall"},
    new Person{FirstName="Jamie", LastName="Oliver"},
    new Person{FirstName="Delia", LastName="Smith"}
};
 
public ObservableCollection<Person> Chefs
{
    get
    {
        return chefs;
    }
    set
    {
        chefs = value;
        RaisePropertyChanged();
    }
}

That loads up the collection and you can see the properties which are to be bound.
There's a fair bit of code there but the thing to focus on is the setter for SelectedChef.
This will be fired as the user picks a Chef out the list because  the binding will set the Source property and SelectedChef will be set.
DoSomethingWhenChefChanged() will then be invoked,
This is the equivalent to a SelectedIndexChanged handler.

Commands

You will use Commands a lot.  In usage this means binding something to a command.  Often to provide a Command property on a control.
The most common use of commands is probably as a button click equivalent.
As well as offering the facility to invoke some piece of code in your viewodel, commands also offer a mechanism to tell the thing they are bound to whether they CanExecute or not.  In turn this usually will disable such a control.  This is a detail which will distract somewhat so we will gloss over this at the moment - but the reader should investigate CanExecute later.

Not that you ever would do, but do not ever try and handle a click event as well as bind a command – they are mutually exclusive.

Out the box in wpf there is the ICommand interface, which is a bit clunky if you use it directly.  Most devs use an MVVM framework such as MVVM Light or PRISM   which offer developer friendly wrappers for iCommand – RelayCommand and DelegateCommand respectively.

The author prefers MVVM Light and Relaycommand.
There are several ways to set up a Relaycommand.
The simplest approach is to define a method which the command will point at and wire that up in the ViewModel constructor.

public RelayCommand MethodCommand {get; private  set;}
 
private void  ExplicitMethod()
{
    // Do some logic here
}
 
public MainWindowViewModel()
{
    MethodCommand = new  RelayCommand(ExplicitMethod);
}

This particular command takes no parameters and has no canexecute in order to keep it as easy to understand a possible.
It's quite common for commands to either require no parameter or  for the method to use private members of the viewmodel.
For example, if you are doing something to an entry which is selected then you can bind that selected item to a property and use that in the method.
You can read more about RelayCommand and how to deal with CanExecute in Laurent Bugnion's article.

KeyBinding / Input Gestures

You can associate a command with an input key – usually a key chord. This would usually be at window level but inputbindings can have scope such as usercontrol.  This is usually less meaningful though since "hot" keys are expected to be associated with an application and hence window rather than some only working when some panel somewhere in there has focus.

<Window.InputBindings>
    <KeyBinding Command="{Binding AnonCommand}"
                CommandParameter="This is an anonymous method"
                Key="X"
                Modifiers="Control" />
</Window.InputBindings>

Here the KeyBinding will invoke the bound command AnonCommand and pass it a parameter "This is an anonymous method".  This happens when the user holds down the Control button and presses the "x" key as well.

In the ViewModel:

private RelayCommand<string> anonCommand;
public RelayCommand<string> AnonCommand
{
    get
    {
        return anonCommand
            ?? (anonCommand = new RelayCommand<string>
                (x =>
                {
                    // Do something with string x
                }));
    }
}

You can see this is a full property with just a getter, no setter.  The backing variable will be set to an anonymous method ( in the curly braces ) the first time the command is called and then after that the backing variable will be returned.
The string "This is an anonymous method"  is passed in as x to that anonymous method.
You can follow this by putting a break point on that first curly brace after the =>.  
Run the app with an f5.
Press Ctrl+X and when it hits your break point hover over x to check the string value.
The command parameter is shown here largely to illustrate passing a parameter to a command of this sort.
In the instance of KeyBindings, it is unusual to have a parameter at all.

You can associate such KeyBindings with a command used by a button or something similar.
This is a great way to offer shortcut keys for menus or the like.

One thing to bear in mind with KeyBindings is that you don't get a free pass with the key combinations.
You need to be aware of the usual windows keys and avoid ones which are already taken or have a recognised meaning. Those key chords which have meaning in controls ( eg textbox ) will be handled by them if they have focus.  This can make picking a valid key combination quite a chore.

AccessText

An alternative approach to consider for hotkeys uses AccessText - this is often considered most appropriate to buttons the user can see.

<Button Command="{Binding MethodCommand}" Margin="0,40,0,0">
    _A Button bound to a Command 
</Button>

Here, if you press Alt+A the MethodCommand will be invoked, just like you clicked that button.
In theory the user should see that A from "_A Button bound to a Command" underlined.  In practice this is not reliable as you can see from the screeen shot and that A only becomes underlined once you press Alt. This might be considered a plus or a problem, depending on your viewpoint.

Another oddity of AccessKeys is that when a control has focus you don't need to press the Alt as well as the character.  This is particularly noticeable where you have a menu. 
This particular aspect is sufficient for some teams to choose to always use KeyBindings instead since they feel the slight inconvenience is small price to pay for more consistent behaviour. 
In case you were wondering, a TextBox in a menu takes an accesskey with no modifier as regular input if the user types a key happens to be an AccessKey into it for another menuitem.  If the user doesn't get their focus on  that textbox and starts typing then that's another story of course.

Hyperlinks are very similar to buttons in that they are going to fire a command, except they look different and are probably going to have a parameter handed to the command.  Hyperlinks are one of those controls whose functionality if fairly often in a rather grey area. You might consider implementing a hyperlink purely in xaml rather than involving any viewmodel at all.
Hyperlink is quite strange since it's an inline.  You need to put it inside some other control before it works.  A TextBlock is the usual candidate for this.

<TextBlock>
    <Hyperlink Command="{Binding NavigateCommand}"
        CommandParameter="http://en.wikipedia.org/wiki/Grey">
        Wiki - Grey
    </Hyperlink>
</TextBlock>

The content "Wiki - Grey" will appear as the text of the hyperlink whilst clicking on this will invoke the bound NavigateCommand and pass it a URI.
In the ViewModel:

public MainWindowViewModel()
{
    MethodCommand = new  RelayCommand(ExplicitMethod);
    NavigateCommand = new  RelayCommand<string>(NavigateExecute);
}
 
public RelayCommand<string> NavigateCommand { get; private  set; }
 
private void  NavigateExecute(string  uri)
{
    System.Diagnostics.Process.Start(uri);
}

Again, this command is the sort which connects to a method wired up in the constructor. This time a string parameter is passed - as a regular parameter by value.
The ViewModel then uses Process.Start on the URI.  Because http is associated with browsing the web the default web browser will start up and show that URI.  This isn't breaking any principles of MVVM because the web page isn't a view at all.  At least not in MVVM terms.

This approach is useful for presenting dynamic read only data.  You could present some reporting via a web site, help pages might be supplied for many products you're selling or maybe you just want to show terms and conditions from a software package which is distributed world wide by numerous agents who all want "their" pages to be branded differently.  
You might think that mixing some web in with a Windows desktop app is a  bit strange but this is very useful for some software packages.  Especially when the software house is writing the one package to be branded and skinned for numerous other companies.

Hyperlinks are included here also to highlight the fact that not all things the user sees are Views. 

Medium Complexity

These are slightly more complicated.

EventTrigger

This is one of those things which can get the learner quite excited.  AHAH! You mean I can put an event handler in xaml and call a command?

Yes you can, but you won’t be using this very much.

The first thing to realise is that the plain EventTrigger has no direct way to run a command. 
As a result this tends to be more useful for view orientated effects.

Here a rectangle changes colour as you mouseover and back when the mouse leaves a rectangle.

<Rectangle Height="40">
    <Rectangle.Triggers>
        <EventTrigger  RoutedEvent="MouseEnter">
            <BeginStoryboard >
                <Storyboard >
                    <ColorAnimation
                       To="Red"
                       Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
                       Duration="0:0:1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger  RoutedEvent="MouseLeave">
            <BeginStoryboard >
                <Storyboard >
                    <ColorAnimation
                       To="Pink"
                       Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
                       Duration="0:0:.5"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Rectangle.Triggers>
</Rectangle>

Note that the event must be a routed event - not all events are routed and you need to check in MSDN what that event is.
If you were to just use TargetProperty="Fill" then this will error.  Fill is a brush rather than a color, which is why the markup looks a bit long winded in that it goes and find the colour of the solidcolorbrush which is set to the fill and animates that color.
Instead of color that animation could change some other dependency property on the control BUT there is a problem here in that when you do so it will over-write any binding on that.  So for example:

<Rectangle Height="{Binding RectangleHeight, Mode=TwoWay}">
    <Rectangle.Triggers>
        <EventTrigger  RoutedEvent="MouseEnter">
            <BeginStoryboard >
                <Storyboard >
                    <DoubleAnimation
                       To="30"
                       Storyboard.TargetProperty="(Rectangle.Height)"
                       Duration="0:0:1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>

Will never fire the setter of RectangleHeight in the ViewModel because you just over wrote the binding with a value. 

There are complicated ways round this involving things like extra attached dependency properties or putting binding in a dependency object viewmodel but these are advanced techniques.  Since this article is aimed at beginners they are by definition outside the scope of this article and best left until you've used easier techniques.

A more practical approach is to use functionality from Blend. 

Advanced Technique

These come with a health warning for the new developer - they are in this section for good reason.

Interaction Triggers

This particular section is by far the most useful of these events-to-command mechanisms in that it is useful in every view you will want to do any validation.
It is, however, quite complicated and pushes the scope of this article beyond what a beginner ought to be tackling.
Put this on your list to learn later.

The problem this solves is that data conversion between view and viewmodel fails before anything gets to the viewmodel at all.
In order for the view to tell the viewmodel there has been any sort of a problem you need markup and code to tell it.
The following is used in a scope encompassing all your editing:

<i:Interaction.Triggers>
    <local:RoutedEventTrigger RoutedEvent="{x:Static Validation.ErrorEvent}">
        <e2c:EventToCommand
                                Command="{Binding EditVM.TheEntity.ConversionErrorCommand, Mode=OneWay}"
                                EventArgsConverter="{StaticResource BindingErrorEventArgsConverter}"
                                PassEventArgsToCommand="True" />
    </local:RoutedEventTrigger>
    <local:RoutedEventTrigger RoutedEvent="{x:Static Binding.SourceUpdatedEvent}">
        <e2c:EventToCommand
                                Command="{Binding EditVM.TheEntity.SourceUpdatedCommand, Mode=OneWay}"
                                EventArgsConverter="{StaticResource BindingSourcePropertyConverter}"
                                PassEventArgsToCommand="True" />
    </local:RoutedEventTrigger>
</i:Interaction.Triggers>

Since this is really out of scope the idea is to make the reader aware the technique exists and can be pretty much copied.  The following therefore rather glosses over a number of things as they're a bit mind numbing for the target audience.

The code uses a mix of technologies.
Interaction.Triggers come from Blend.
That RoutedEventTrigger inherits from System.Windows.Interactivity.EventTriggerBase.  It's a custom trigger which is necessary in order to deal with Validation.ErrorEvent.
EventToCommand comes from MVVM Light and is chosen because this makes it relatively easy to pass in a parameter to the command containing the list of errors.
As the property EventArgsConverter implies, EventToCommand expects use of a converter and this largely does two things - it gets the bindingexpression the error is coming from and works out the name of the property, it also decides whether the error is to be added or removed from the collection of errors for that binding.
If this seems hard then maybe you're better coming back to it later when you're a bit more confident.  Or you can just copy the classes and markup.

The RoutedEventTrigger:

public class  RoutedEventTrigger : EventTriggerBase<DependencyObject>
{
    RoutedEvent routedEvent;
    public RoutedEvent RoutedEvent
    {
        get
        {
            return routedEvent;
        }
        set
        { 
            routedEvent = value;
        }
    }
 
    public RoutedEventTrigger()
    {
    }
    protected override  void OnAttached()
    {
        Behavior behavior = base.AssociatedObject as  Behavior;
        FrameworkElement associatedElement = base.AssociatedObject as  FrameworkElement;
        if (behavior != null)
        {
            associatedElement = ((IAttachedObject)behavior).AssociatedObject as  FrameworkElement;
        } 
        if (associatedElement == null)
        {
            throw new ArgumentException("This only works with framework elements");
        }
        if (RoutedEvent != null)
        {
            associatedElement.AddHandler(RoutedEvent, new  RoutedEventHandler(this.OnRoutedEvent));
        }
    }
    void OnRoutedEvent(object sender, RoutedEventArgs args)
    {
         base.OnEvent(args);
    }
    protected override  string GetEventName()
    {
        return RoutedEvent.Name;
    }
}

( The origin of this class is lost in the mists of time, it may have been copied this or adapted from somewhere ).
This is there to handle a Validation.Error routed event in an eventtrigger.  Think of it as a sort of adapter if you like.

The "errors" are then passed into a bound command which is in the base entity which all entity framework entities inherit from.
 

public class  BaseEntity : NotifyUIBase, INotifyDataErrorInfo
{
    // From Validation Error Event
    private RelayCommand<PropertyError> conversionErrorCommand;
    public RelayCommand<PropertyError> ConversionErrorCommand
    {
        get
        {
            return conversionErrorCommand
                ?? ( conversionErrorCommand = new  RelayCommand<PropertyError>
                    (PropertyError =>
                   {
                       if (PropertyError.Added)
                       {
                           AddError(PropertyError.PropertyName, PropertyError.Error, ErrorSource.Conversion);
                       }
                       FlattenErrorList();
                   }));
        }
    }

These errors are actually add and remove notifications which is why that code is only interested in added ones.  The validation error passed in is then used in the wider error handling and we better stop at this point before we head off the reservation.

EventToCommand requires a converter.

public class  BindingErrorEventArgsConverter : IEventArgsConverter
{
    public object  Convert(object  value, object  parameter)
    {
        ValidationErrorEventArgs e = (ValidationErrorEventArgs)value;
        PropertyError err = new  PropertyError();
        err.PropertyName = ((System.Windows.Data.BindingExpression)(e.Error.BindingInError)).ResolvedSourcePropertyName;
        err.Error = e.Error.ErrorContent.ToString();
        // Validation.ErrorEvent fires for addition and removal
        if (e.Action.ToString() == "Added")
        {
            err.Added = true;
        }
        else
        {
            err.Added = false;
        }
        return err;
    }
}

That code obtains a reference to the binding the error is coming from in order to get the name of the property involved.
The errorcontent is the string describing the error.
As mentioned earlier, there will be an event raised for removal of errors as well as addition.
The error handling is only interested in added errors.
 
OK, this is tricky stuff. For now, you are probably best copying the pattern out of a sample without trying to understanding completely why it does what. The error handling in the sample is re-usable.

The technique is used in the Entity Framework MVVM Walk Through 2 sample.

Behaviors

Some dependency properties turn out to be read only.  This is a nuisance since it can fool you into starting to code right up into a blind alley.

IsMouseover is one of these properties which is trickier than it might first appear.

Say you want to do something in your viewmodel as the user rolls his mouse over a control in your view.

You look up the control on MSDN (say it’s a Button) and you look at the properties.

You can see the IsMouseOver property… there it is and at first glance it’s a dependency property so... let’s bind it.

In Visual Studion type in IsMouseOver inside the button tag…
That’s odd.

Intellisense doesn’t find it and it basically doesn’t work.

This is one of the gotchas of dependency properties.

When you take a closer look at IsMouseOver.

You will see it’s read only:

“public bool IsMouseOver { get; }”

You can’t bind to read only dependency properties.

Not even if you bind oneway.

One way round this is to add a behavior with a Dependency Property. 
You can more read about Attached Behaviors here.

What you’re doing, essentially, is adding some event handling code to your control which then sets your own property.

Only this new property is a “proper” dependency property rather than just a read only one and you will be able to bind it.

Here's an IsMouseOver Behavior which adds IsMouseOverAP dependency property and some functionality which sets it.

class IsMouseOverBehavior : Behavior<FrameworkElement>
{
    public bool  IsMouseOverAP
    {
        get { return (bool)GetValue(IsMouseOverAPProperty); }
        set { SetValue(IsMouseOverAPProperty, value); }
    }
 
 
    public static  readonly DependencyProperty IsMouseOverAPProperty = DependencyProperty.RegisterAttached(
                      "IsMouseOverAP",
                      typeof(bool),
                      typeof(IsMouseOverBehavior));
    protected override  void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.MouseEnter += AssociatedObject_MouseEnter;
        this.AssociatedObject.MouseLeave += AssociatedObject_MouseLeave;
    }
 
    void AssociatedObject_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
    {
        FrameworkElement el = sender as  FrameworkElement;
        SetValue(IsMouseOverAPProperty, false);
    }
 
    void AssociatedObject_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
    {
        FrameworkElement el = sender as  FrameworkElement;
        SetValue(IsMouseOverAPProperty, true);
    }
    protected override  void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.MouseEnter -= AssociatedObject_MouseEnter;
        this.AssociatedObject.MouseLeave -= AssociatedObject_MouseLeave;
    }
 
}

Josh's article explains this sort of thing pretty well and it's probably an idea to read that first.
If you're new to Dependency Properties then it's probably an idea to read up on them as well.
In short, IsMouseOverAP is one of these strange dependency property things.  The main attraction here is that this gives us a bool property which can be bound successfully.
OnAttached and OnDetaching fire as the framework element is set up and torn down in the View.
As you can see these are used to attach and remove event handlers.
As the mouse enters and leaves, our new dependency property is set appropriately.
That SetValue avoids over-writing any binding.

The markup using that:

<Button>
    <i:Interaction.Behaviors>
        <local:IsMouseOverBehavior IsMouseOverAP="{Binding IsMouseOverButton, Mode=TwoWay}"  />
    </i:Interaction.Behaviors>
    Mouse Over Button
</Button>

Note that the dependency property is a property of the behavior as welll as the control it's attached to.
Another thing to watch out for is that Mode=TwoWay.  That has quite a strange effect in that if you don't set it your dependency property won't set the bound property in the ViewModel.
Behaviors come from blend so you also need to import the namespace for that:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

You will, of course, have noticed that those are event handlers there.  So yes, this is one of those times when you're going to use event handlers.
Bear in mind that these are acting in the view.  The thing that connects that property up with the viewmodel is binding.  You could instantiate that viewmodel and set IsMouseOver in a piece of test code without the View.

Behaviors aren’t code which goes in your code-behind, they don’t go in your viewmodel either.  You’re not going to be able to automate tests on them.

You  manually test these carefully and then re-use the same behavior.

In most teams this is considered acceptable and of course since you re-use the same code in all views then the impact on overall code coverage will be minimised.

Sometimes such behaviors are deliberately placed in a separate dll for re-use and so there is no code in your solution dragging down stats. 

Even if you don’t use automated testing or nobody cares if your code coverage drops ( where do you work again? ) this is still a good thing.

Re-using code means you are more likely to find a problem and it can be fixed in one place.

So that’s a great idea then?

Yes, with caveats.

At the risk of stating the obvious – try and avoid very complicated behaviors.

The simpler these things are, the easier you can manually test them.

 

ViewModel EventHandlers

There are some objects which you instantiate in the ViewModel and you can attach handlers to these.

A fairly common example of this is ObservableCollection<t>  which you will be using for any collection where you add and or remove entries and expect the view to respond.  You can handle CollectionChanged to drive processing - eg when the user adds a new entry in a bound datagrid.

Let's bind another button to a command which adds to that Chefs collection.
Add a handler to CollectionChanged of Chefs:

public RelayCommand AddAChef { get; private  set; }
private void  AddAChefExecute()
{
    Chefs.Add(new Person { FirstName = "Rick", LastName = "Stein" });
}
void Chefs_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    UiMessage = "You added " + ((Person)e.NewItems[0]).FullName;
}
public MainWindowViewModel()
{
    AddAChef = new  RelayCommand(AddAChefExecute);
    Chefs.CollectionChanged += Chefs_CollectionChanged;
 
    MethodCommand = new  RelayCommand(ExplicitMethod);
    NavigateCommand = new  RelayCommand<string>(NavigateExecute);
}

By now you should be reasonably familiar with the binding of commands and the RelayCommand code.
The event handler is passed the list of changes to the collection and the code takes rather a shortcut to display that we add Rick Stein to the collection.
Drop the combo down and you will see that the Combobox shows his entry.
That appears in the list because the bound itemscontrol is also listening to that CollectionChanged event from the Chefs  Observablecollection.

Last Resort

This isn't so much an advanced technique as one you should only really use if you know the other ones, considered them and know that none will work.

In rare circumstances you might find there is no real way to get round it.   You need to handle an event in code behind and that absolutely must communicate to something which is a viewmodel.

The way to do this is using an event aggregator.  In MVVMLight that would mean messenger.

There's a simplified version of that error handler in the BaseWindow of the Keeping Your MVVM Views DRY sample

public partial  class BaseWindow : Window
{
    private void  Window_Error_Event(object sender, RoutedEventArgs args)
    {
        ValidationErrorEventArgs e = (ValidationErrorEventArgs)args;
        PropertyError err = new  PropertyError();
        err.PropertyName = ((System.Windows.Data.BindingExpression)(e.Error.BindingInError)).ResolvedSourcePropertyName;
        err.Error = e.Error.ErrorContent.ToString();
        if (e.Action.ToString() == "Added")
        {
            err.Added = true;
        }
        else
        {
            err.Added = false;
        }
        Messenger.Default.Send<PropertyError>(err);
    }
    public BaseWindow()
    {
        EventManager.RegisterClassHandler(typeof(Window), Validation.ErrorEvent, new RoutedEventHandler(Window_Error_Event));
    }

That should look somewhat familiar in that it's subscribing to the error event for the whole window and using quite similar code to the behavior based approach.
It then sends the error as an MVVM Light Message.

In the Viewmodel constructor, that message is subscribed to and an anonymous method will be invoked when one of these messages is received:

public MainWindowViewModel()
{
    Messenger.Default.Register<PropertyError>(this, propertyError =>
    {
        if (propertyError.Added)
        {
            TheResult = propertyError.Error;
        }
        else
        {
            TheResult = "OK";
        }
    });
}

If you don't care about test coverage then it's largely a matter of taste whether you prefer messenger or eventtocommand for some purposes.
As the heading implies, the author's preference is to minimise use of messenger.
It is a very useful technique though and you can read more in the Communicating Between Classes article.

Acceptable Events

As mentioned way up there, if an event in code behind only changes something in the view then this might well be a reasonable approach.

There are a few caveats to consider.

Is there no MVVM way?

Would any alternative be much more complicated?

At the end of the day software development is not an academic pastime. We’re trying  to produce some application which helps a user do something.

This application takes time to develop and people’s time costs money.

The quicker it’s working, the lower the cost.

Similarly, applications cost money to maintain.

A solution which is easier to maintain will be cheaper and quicker to maintain.

In business, cost is King.

Summary

There are a bunch of techniques which replace use of code event handlers in MVVM.

Sometimes these are sort of standardised eventhandlers.

One way or another you never need an eventhandler in code behind which needs a reference to anything outside the view.

PS

That grumpy team lead is of course someone totally different from the Author ;^)

You’re safe.

If you want that code walk through with your Team Lead to be uneventful then don’t use events.

See Also

WPF Resources on the Technet Wiki
Event handling in an MVVM WPF application

Other Resources

Some articles focus just on one specific aspect of this subject.  Some are more general - and are aimed at more experienced developers.  Very few attempt to cover the entire subject.
None explain both the reasons or explain as many techniques.  That's the reason this article was written.

Commands, RelayCommands and EventToCommand
The MVVM Light Messenger In-Depth
WPF Apps With The Model-View-ViewModel Design Pattern
Adventures in MVVM – Binding Commands to ANY Event
Binding WPF Events to MVVM ViewModel Commands