Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resharper Create Custom Refactor for ReactiveUI's ReactiveObject

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...

like image 975
Robert Petz Avatar asked Dec 16 '22 05:12

Robert Petz


1 Answers

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!

like image 169
Igal Tabachnik Avatar answered Dec 21 '22 22:12

Igal Tabachnik