MVVM Light V4 preview (BL0014) release notes

MVVM_WhiteText_BL0014

I just pushed to Codeplex an update to the MVVM Light source code. This is an early preview containing some of the features that I want to release later under the version 4. If you find these features useful for your project, please download the source code and build the assemblies. I will appreciate greatly any issue report.

This version is labeled “V4.0.0.0/BL0014”. The “BL” string is an old habit that we used in my days at Siemens Building Technologies, called a “base level”. Somehow I like this way of incrementing the “base level” independently of any other consideration (such as alpha, beta, CTP, RTM etc) and continue to use it to tag my software versions. In Microsoft parlance, you could say that this is an early CTP of MVVM Light V4.

Caveat

The code is unit tested, but as we all know this does not mean that there are no bugs Smile This code has not yet been used in production. Again, your help in testing this is greatly appreciated, so please report all bugs to me!

What’s new?

The following features have been implemented:

Misc

  • Various “maintenance work”.
  • All WPF assemblies (that is .NET35 and .NET4) now allow partially trusted callers. It means that you can use them in am XBAP in partial trust mode.

Testing

  • Various test updates
  • Added Windows Phone 7 unit tests

Note: For Windows Phone 7, due to an issue in the unit test framework, not all tests can be executed. I had to isolate those tests for the moment. The error was reported to Microsoft.

ViewModelBase

  • The constructor is now public to allow serialization (especially useful on the phone to tombstone the state).
  • ViewModelBase.MessengerInstance now returns Messenger.Default unless it is set explicitly. Previously, MessengerInstance was returning null, which was complicating the code.
  • Two new ways to raise the PropertyChanged event have been added. See below for details.

Messenger

  • Updated the IMessenger interface with all public members from the Messenger class. Previously some members were missing.
  • A new Unregister method is now available, allowing to unregister a recipient for a given token.

RelayCommand

  • RaiseCanExecuteChanged now acts the same in Windows Presentation Foundation than in Silverlight. In previous versions, I was relying on the CommandManager to raise the CanExecuteChanged event in WPF. However, it was found to be too unreliable, and a more direct way of raising the event was found preferable. See below for details.

Raising the PropertyChanged event

A very much requested update is now included: the ability to raise the PropertyChanged event in a viewmodel without using “magic strings”. Personally, I don’t see strings as a major issue, thanks to two features of the MVVM Light Toolkit:

  • In the DEBUG configuration, every time that the RaisePropertyChanged method is called, the name of the property is checked against all existing properties of the viewmodel. Should the property name be misspelled (because of a typo or refactoring), an exception is thrown, notifying the developer that something is wrong. To avoid impacting the performance, this check is only made in DEBUG configuration, but that should be enough to warn the developers in case they miss a rename.
  • The property name is defined as a public constant in the “mvvminpc” code snippet. This allows checking the property name from another class (for example if the PropertyChanged event is handled in the view). It also allows changing the property name in one place only.

However, these two safeguards didn’t satisfy some of the users, who requested another way to raise the PropertyChanged event. In V4, you can now do the following:

Using lambdas

private int _myProperty;
public int MyProperty
{
    get
    {
        return _myProperty;
    }

    set
    {
        if (_myProperty == value)
        {
            return;
        }

        _myProperty = value;
        RaisePropertyChanged(() => MyProperty);
    }
}

This raises the property changed event using a lambda expression instead of the property name. Light reflection is used to get the name. This supports Intellisense and can easily be refactored. You can also broadcast a PropertyChangedMessage using the Messenger.Default instance with:

private int _myProperty;
public int MyProperty
{
    get
    {
        return _myProperty;
    }

    set
    {
        if (_myProperty == value)
        {
            return;
        }

        var oldValue = _myProperty;
        _myProperty = value;
        RaisePropertyChanged(() => MyProperty, oldValue, value, true);
    }
}

Using no arguments

When the RaisePropertyChanged method is called within a setter, you can also omit the property name altogether. This will fail if executed outside of the setter however. Also, to avoid confusion, there is no way to broadcast the PropertyChangedMessage using this syntax.

private int _myProperty;
public int MyProperty
{
    get
    {
        return _myProperty;
    }

    set
    {
        if (_myProperty == value)
        {
            return;
        }

        _myProperty = value;
        RaisePropertyChanged();
    }
}

The old way

Of course the “old” way is still supported, without broadcast:

public const string MyPropertyName = "MyProperty";
private int _myProperty;
public int MyProperty
{
    get
    {
        return _myProperty;
    }

    set
    {
        if (_myProperty == value)
        {
            return;
        }

        _myProperty = value;
        RaisePropertyChanged(MyPropertyName);
    }
}

And with broadcast:

public const string MyPropertyName = "MyProperty";
private int _myProperty;
public int MyProperty
{
    get
    {
        return _myProperty;
    }

    set
    {
        if (_myProperty == value)
        {
            return;
        }

        var oldValue = _myProperty;
        _myProperty = value;
        RaisePropertyChanged(MyPropertyName, oldValue, value, true);
    }
}

Performance considerations

It is notorious that using reflection takes more time than using a string constant to get the property name. However, after measuring for all platforms, I found the differences to be very small. I will measure more and submit the results to the community for evaluation, because some of the results are actually surprising (for example, using the Messenger to broadcast a PropertyChangedMessage does not significantly increase the time taken to raise the PropertyChanged event and update the bindings). For now, I submit this code to you, and would be delighted to hear about your own results.

Raising the CanExecuteChanged event manually

In WPF, until now, the CanExecuteChanged event for a RelayCommand was raised automatically. Or rather, it was attempted to be raised, using a feature that is only available in WPF called the CommandManager. This class monitors the UI and when something occurs, it queries the state of the CanExecute delegate for all the commands. However, this proved unreliable for the purpose of MVVM: Since very often the value of the CanExecute delegate changes according to non-UI events (for example something changing in the viewmodel or in the model), raising the CanExecuteChanged event manually is necessary.

In Silverlight, the CommandManager does not exist, so we had to raise the event manually from the start. This proved more reliable, and I now changed the WPF implementation of the RaiseCanExecuteChanged method to be the exact same in WPF than in Silverlight.

For instance, if a command must be enabled when a string property is set to a value other than null or empty string, you can do:

public MainViewModel()
{
    MyTestCommand = new RelayCommand(
        () => DoSomething(),
        () => !string.IsNullOrEmpty(MyProperty));
}

public const string MyPropertyName = "MyProperty";
private string _myProperty = string.Empty;
public string MyProperty
{
    get
    {
        return _myProperty;
    }

    set
    {
        if (_myProperty == value)
        {
            return;
        }

        _myProperty = value;
        RaisePropertyChanged(MyPropertyName);
        MyTestCommand.RaiseCanExecuteChanged();
    }
}

Logo update

I made a minor change to the logo: Some people found the lack of the word “light” (as in MVVM Light Toolkit) confusing. I thought it was cool, because the feather suggests the idea of lightness, however I can see the point. So I added the word “light” to the logo. Things should be quite clear now. Smile

What’s next?

This is only the first of a series of releases that will bring MVVM Light to V4. In the next weeks, I will continue to add some very requested features and correct some issues in the code. I will probably continue this fashion of releasing the changes to the public as source code through Codeplex. I would be very interested to hear what you think of that, and to get feedback about the changes.

Cheers,

Laurent

 

Print | posted on Tuesday, February 08, 2011 12:24 AM

Feedback

# re: MVVM Light V4 preview (BL0014) release notes

left by Ant at 2/8/2011 2:26 AM Gravatar
Thanks Laurent!!! :)

Looking forward to downloading and playing with the bits tonight.

In the future, I am very interested to know what type of changes you would like to make to the LocatorService.

Thank again,
Ant

# re: MVVM Light V4 preview (BL0014) release notes

left by Craig D at 2/8/2011 3:59 AM Gravatar
Excellent :)
+1 for lambdas

# re: MVVM Light V4 preview (BL0014) release notes

left by Corrado Cavalli at 2/8/2011 6:56 AM Gravatar
Wow! Nice improvements Laurent!

# re: MVVM Light V4 preview (BL0014) release notes

left by John Papa at 2/8/2011 7:28 AM Gravatar
Nice updates Laurent. Love to see the VMLocator changes we batted around too, to your starter template.

I appreciate that you keep it all light ... that's they key to adoption.

# re: MVVM Light V4 preview (BL0014) release notes

left by Fox at 2/8/2011 11:15 AM Gravatar
Good job Laurent.

I like all changes. The PropertyChanged is a really good idea.

I always delete some code from VMLocator and adapt it to launch all the DI infrastructure. I think that the VMLocator have too much verbose code (Or Im just novice and I don't see the need).

On the other hand, I think that the Messenger have too many options and maybe a little complicated to see. Some doc of how to use the different options of the Messenger would be good.

Well, is time to think of new posts of my mvvm light post series in my blog :P and of course try this V4 on a new project I have on mind.

# re: MVVM Light V4 preview (BL0014) release notes

left by Rick Ratayczak at 2/8/2011 12:12 PM Gravatar
Laurent, can you implement INotifyPropertyChanging in the view model base please?

# re: MVVM Light V4 preview (BL0014) release notes

left by John Demigor at 2/9/2011 11:19 PM Gravatar
Laurent, could you please make it KindOfMagic compatible?
This way implementation of INotifyPropertyChanged is nearly zero-effort.

http://visualstudiogallery.msdn.microsoft.com/d5cd6aa1-57a5-4aaa-a2be-969c6db7f88a?SRC=Home

# re: MVVM Light V4 preview (BL0014) release notes

left by Laurent at 2/10/2011 12:12 AM Gravatar
@ John: Hi,

I don't think I will. The "spirit" of MVVM Light is to keep things simple and easy to understand. The "magic" is exactly what I am trying to avoid in the core package. I have studied multiple ways to solve the issue (modifying the IL, Mono.Cecil, etc) and talked to many people about it (including Anders Helsjberg who was kind enough to listen and comment on my ramblings) and I believe that a solution will come from the framework itself. In the mean time, I prefer to stick to the current implementation for MVVM Light, being understood that I am also doing my best to not come in the way of solutions like KindOfMagic. As far as I understand, it should be easy enough to create a VM compatible with MVVM Light and using KindOfMagic (or any other code injection solution for that matter).

Thoughts?

Cheers,
Laurent

# re: MVVM Light V4 preview (BL0014) release notes

left by John Demigor at 2/10/2011 3:03 PM Gravatar
I understand your reasons to avoid dependencies, but implementing things like lambda- or callstack based RaisePropertyChanged is like to shoot yourself in the foot.

The WP7 phones have not the fastest processed, compared to desktop solutions, this way, you encourage people to go simple, but wrong way, putting the whole platform in danger.

I don't know, when MS natively addresses this issue, already like 6 years gone unnoticed. Maybe in 2015 will get the so-needed solution, who knows.

But what's wrong with adding two public attributes and applying them to your core INPC-class, effectively making all derived classes INPC-compatible during build time.

I know, one can do it yourself. But maybe, being part of such well-known MVVM framework, will bring the need of this concept closer to Microsoft understanding.

# re: MVVM Light V4 preview (BL0014) release notes

left by Laurent Bugnion at 2/10/2011 4:41 PM Gravatar
Hi,

Thanks for following up. I do totally hear your arguments (and your frustration). I will try again the Mono.Cecil solution and might reconsider.

About the new RaisePropertyChanged methods, I did some measurements on all platforms and was interested to find out that the loss in performance is really very small (including on WP7). I will publish these results later.

As for Microsoft, believe me, they know about the issue. We keep banging about that :) Adding the solution to MVVM Light will not make them go faster, unfortunately.

Again, thanks for the feedback, and for making me reconsider.

Cheers,
Laurent

# re: MVVM Light V4 preview (BL0014) release notes

left by Rick Ratayczak at 2/10/2011 6:22 PM Gravatar
It's just like INotifyPropertyChanged, except it's raised right before you set the property value.

# re: MVVM Light V4 preview (BL0014) release notes

left by Charles Lecours at 5/24/2011 4:41 PM Gravatar
Hi Laurent,

I have checked the framework for a while and I don't really understand what changed in the Message.Cleanup method as in the V3 there is a Unregister method too.

Thanks again,
Charles

# re: MVVM Light V4 preview (BL0014) release notes

left by Matti at 10/5/2011 10:14 PM Gravatar
In which way the Relay Command CanExecuteChanged was unreliable?

The new implementation seems to force any component interested changing the CanExecute state to have a reference to the command or some extra code to trigger the callback.

I miss the old implementation. Couldn't it be at least somehow optionally still in?

Thanks,
Matti

# re: MVVM Light V4 preview (BL0014) release notes

left by Niclas at 12/21/2011 10:16 PM Gravatar
What happend to the parameter-less RaisePropertyChanged(). Can find it in the libs?
Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: