4

So I have a ton of viewmodels and models in my code that require each property to use the ReactiveUI way of observing their changes:

private bool _myProperty;
public Boolean MyProperty
{
    get { return _myProperty; }
    set { this.RaiseAndSetIfChanged(ref _myProperty, value); }
}

Using Resharper I can convert this:

public Boolean MyProperty { get; set; }

Into this:

private bool _myProperty;
public Boolean MyProperty
{
    get { return _myProperty; }
    set { _myProperty = value; }
}

Then I have to manually convert it into the first code snippet above to get my ReactiveUI functionality incorporated.

What I'm trying to figure out is if there is a way to write a custom refactoring for Resharper that will allow me to add a 'Convert to Reactive Property' shortcut to the tool menu that appears when the cursor is on top of a simple property member? (on top of the already existing 'Convert to auto-property' and 'Convert to property with change notification' options already there.

Any help is greatly appreciated! This would save me a TON of time when coding...

Ana Betts
  • 73,868
  • 16
  • 141
  • 209
Robert Petz
  • 2,718
  • 4
  • 23
  • 52

2 Answers2

9

Out of the box, ReSharper supports ReactiveUI's ReactiveUI.raisePropertyChanged(string) overload to turn an automatic property into a property with change invocation, i.e.:

Turns this:

Into this:

This is done by ReSharper's support for INotifyPropertyChanged that was introduced in ReSharper 7. The way it works, is that the ReactiveUI.raisePropertyChanged(string) method is decorated with ReSharper's Annotation attribute called [NotifyPropertyChangedInvocator]. This attribute, when decorating a method with a particular signature, on a type that implements the INotifyPropertyChanged interface will automatically allow ReSharper to use it as the 'change notification' refactoring.

In your case, with relatively small amount of code, you can utilize the same mechanism. Your RaiseAndSetIfPropertyChanged method, however, needs to have a particular signature. What you could do is, create an abstract class, deriving from ReactiveObject, and implement your method there:

public abstract class ReactiveObjectBase : ReactiveObject
{
    [NotifyPropertyChangedInvocator]
    protected void RaiseAndSetIfPropertyChanged<T>(ref T obj, T value, string propertyName)
    {
        // call real raise method here
    }
}

This method will need to have this exact signature (method name could be different), and it will have to be decorated with the NotifyPropertyChangedInvocator attribute.

After that, simply change the base type of your view models to ReactiveObjectBase, and now you'll be able to turn your automatic properties into change notifications:

Hope this helps!

Igal Tabachnik
  • 31,174
  • 15
  • 92
  • 157
  • Hmmmm...This seems promising, though I'm not sure if I even need to implement anything. Typically, resharper adds the notifyproperrtychangedinvocator annotated method to the class when you use that shortcut, but it doesn't appear to do so with a class that extends from ReactiveObject. As a note, I had a typo in my question, the method to call is 'RaiseAndSetIfChanged' (which is available directly from ReactiveUI), so as I'm seeing and as you said about it supporting the raisePropertyChanged overload from ReactiveUI out of the box I think that this is already setup how I want it lol. – Robert Petz Sep 30 '13 at 20:42
  • Yea looking at the ReactiveUI code on GitHub it appears that the RaiseAndSetIfChanged method just calls the raisePropertyChanged method...with the exception that it also calls the raisePropertyChanging method before it makes the change (which I don't believe will affect me)...answer selected! – Robert Petz Sep 30 '13 at 20:43
  • I had OnPropChanged and SetProperty methods in my base class both attributed with NotifyPropertyChangedInvocator. I removed the attribute from OnPropChanged and both options disappeared from the refactor context menu. Might be a got'cha for someone... – Werewolf Nov 07 '14 at 16:58
2

I never tried it myself but I always wanted to write a R# template myself. According to this post, would that work for you?

private $Type$ $BackingField$;
public $Type$ $Property$
{
  get
  {
    return this.$BackingField$;
  }
  set
  {
    this.RaiseAndSetIfPropertyChanged(ref $BackingField$, value); 
  }
}
meilke
  • 3,280
  • 1
  • 15
  • 31
  • Interesting...not a bad route actually. I was actually trying to figure out how to add it as a refactoring, but I don't mind using it as a template...The only problem is this only really works for new code and not existing properties that need to be modified...If I don't get any responses about creating it as a refactor instead though I'll mark this as the answer – Robert Petz Sep 30 '13 at 20:11
  • Link is dead, any idea where it might be now? – Patrick Szalapski Aug 30 '23 at 16:45