StackOverflowException if base method called.

Jul 20, 2013 at 11:56 PM
Edited Jul 20, 2013 at 11:57 PM
Hello everybody.

My plan is to call the RaisePropertyChanged method of Mvvm Light using attributes. I have this setup:

Attribute:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class RaisePropertyChangedAttribute : HandlerAttribute
{
    public override ICallHandler CreateHandler(IUnityContainer container)
    {
        return new RaisePropertyChangedCallHandler();
    }

    private class RaisePropertyChangedCallHandler : ICallHandler
    {
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            IMethodReturn methodReturn = getNext()(input, getNext);

            string propertyName = input.MethodBase.Name.Substring(4);

            MethodInfo raisePropertyChangedMethod = input.Target.GetType().GetMethod("RaisePropertyChanged",
                BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(string) }, null);
            raisePropertyChangedMethod.Invoke(input.Target, new object[] { propertyName });

            return methodReturn;
        }

        public int Order { get; set; }
    }
}
Registering:
IUnityContainer container = new UnityContainer();
container.AddNewExtension<Interception>();
container.RegisterType<MyViewModel>()
    .Configure<Interception>()
    .SetInterceptorFor<MyViewModel>(new VirtualMethodInterceptor());
ViewModel:
public class MyViewModel : ViewModelBase
{
    [RaisePropertyChanged]
    public virtual bool IsCreating { get; set; }

    public void Run()
    {
        IsCreating = true;
        DoSomething();
        IsCreating = false;
    }

    protected override void RaisePropertyChanged(string propertyName)
    {
        DispatcherHelper.CheckBeginInvokeOnUI(() => base.RaisePropertyChanged(propertyName));
    }
    
    protected override void RaisePropertyChanged<T>(string propertyName, T oldValue, T newValue, bool broadcast)
    {
        DispatcherHelper.CheckBeginInvokeOnUI(() => base.RaisePropertyChanged<T>(propertyName, oldValue, newValue, broadcast));
    }
}
The problem is the base.RaisePropertyChanged call. This call does not invoke the ViewModelBase.RaisePropertyChanged for some reason, it enters the same method again. This causes a StackOverflowException (endless recursion). Has anybody encountered this problem before?
Jul 21, 2013 at 12:31 AM
I finally found the bug. It has nothing to do with unity. My code was based on http://pieterderycke.wordpress.com/2011/07/28/dynamically-adding-raisepropertychanged-to-mvvm-light-viewmodels-using-microsoft-unity/

But there was a check missing which ensured the event is only raised if the property's setter is called. WIth adding a check for the "set_" prefix of the method name, the recursion doesn't occur:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class RaisePropertyChangedAttribute : HandlerAttribute
{
    public override ICallHandler CreateHandler(IUnityContainer container)
    {
        return new RaisePropertyChangedCallHandler();
    }

    private class RaisePropertyChangedCallHandler : ICallHandler
    {
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            IMethodReturn methodReturn = getNext()(input, getNext);

            if (input.MethodBase.Name.StartsWith("set_"))
            {
                string propertyName = input.MethodBase.Name.Substring(4);
                MethodInfo raisePropertyChangedMethod = input.Target.GetType().GetMethod("RaisePropertyChanged",
                    BindingFlags.Instance | BindingFlags.NonPublic, null, new[] {typeof (string)}, null);
                raisePropertyChangedMethod.Invoke(input.Target, new object[] {propertyName});
            }

            return methodReturn;
        }

        public int Order { get; set; }
    }
}