3

I've got a weird little bug which is occurring under MvvmLight v4 (.NET 4 build, v4.0.0.0/BL0016, installed via NuGet). In my project is a view model (which inherits from ViewModelBase) that represents a visual element drawn on a canvas. This view model has typical Top/Left/Width/Height properties, each of which calls RaisePropertyChanged, e.g.

public double Width
{
    get { return _width; }
    set
    {
        if (Math.Abs(_width - value) < DeltaEpsilon)
        {
            return;
        }

        _width = value;
        RaisePropertyChanged();
    }
}

In response to various events, the view model also has a method which calculates the position and dimensions of the visual element, and sets the properties appropriately:

public void CalculateSize()
{
    Width = DoSomeCalculation();
    // Calculate other settings...
}

I have some unit tests in place that verify that calculations are done correctly, and when I run in Debug mode, the tests run fine. However, if I run in Release mode, the tests fail, with the following exception:

SetUp : System.InvalidOperationException : This method can only by invoked within a property setter.
at GalaSoft.MvvmLight.ObservableObject.RaisePropertyChanged()
at MyProject.ViewModels.TableViewModel.CalculateSize() in TableViewModel.cs: line 154

where line 154 on TableViewModel is the Width = DoSomeCalculation() line. In other words, when my method tries to set the property's value, MvvmLight complains that I'm not calling RaisePropertyChanged from within a property setter. I've tried debugging the test (using Reshaper's test debugger), but when I run the debugger, the test passes (maybe debugging a unit test in Resharper forces it into Debug mode, even if in Release mode already?) The error also occurs in the application itself.

Any ideas as to why Release mode would break the code? Is there something in the way the compiler optimises code that breaks the use of the StackTrace in ObservableObject's RaisePropertyChanged() method? Note that the exception above doesn't show the Width setter being entered, it jumps straight from the CalculateSize method to the exception.

David Keaveny
  • 3,483
  • 1
  • 32
  • 47

1 Answers1

3

If you look at the MVVM Light code you can see that RaisePropertyChanged() uses a StackTrace to determine the name of the property. This can be a problem in release mode as described in this post.

Use a different RaisePropertyMethod to circumnavigate this problem - you can use one of the following methods:

RaisePropertyChanged<YourClass>(x => x.Width);

or

RaisePropertyChanged("Width");

Both methods use a different method to determine the name of the property that has changed (the second just uses the property name).

Community
  • 1
  • 1
AxelEckenberger
  • 15,758
  • 3
  • 45
  • 67
  • Although I'd already since posted a link showing the reason for my issue, I'll give you the answer, since you gave a workaround :-) – David Keaveny Jul 21 '11 at 23:08
  • The link just says that there is a problem. In my post I quote another Stackoverflow post that actually explains the reason **why** it is not working. I also pointed Laurent to this issue, see http://twitter.com/LBugnion/status/94173507906318337 for his answer. – AxelEckenberger Jul 22 '11 at 04:40