ReSharper Platform SDK Help

Work with IProperty

What you should know beforehand:

IProperty is one more concept that is used quite often throughout the ReSharper API. Simply put, an IProperty object is able to track the changes, validate new values being assigned, and notify about the changes. IProperty has much in common with signals.

Basic Usage

Examples (?):

For example, the SomeIntProperty parameter of the PropertyProvider class is important for the work of PropertyTester. Once the parameter is updated, PropertyTester is notified about the new value:

public class PropertyProvider { public IProperty<int> SomeIntProperty; public PropertyProvider(Lifetime lifetime) { SomeIntProperty = new Property<int>(lifetime, "PropertyProvider.SomeIntProperty"); } } public class PropertyTester { private readonly PropertyProvider _propertyProvider; public PropertyTester(Lifetime lifetime, PropertyProvider propertyProvider) { _propertyProvider = propertyProvider; _propertyProvider.SomeIntProperty.BeforeChange.Advise(lifetime, args => { if (args.New < 0) args.Cancel = true; }); _propertyProvider.SomeIntProperty.Change.Advise(lifetime, val => MessageBox.ShowInfo($"New property value is {val}")); } public void ChangePropertyValue(int value) { _propertyProvider.SomeIntProperty.Value = value; } }

Global Options

Examples (?):

One more obvious example of how IProperty can be used is global options: once a user changes an option on the Options page, the plugin gets instantly notified about the change.

Text = new Property<string>(lifetime, "OptionsExampleViewModel.Text"); var checkMeOption = settingsStore.BindToContextLive(lifetime, ContextRange.ApplicationWide) .GetValueProperty(lifetime, (MySettingsKey key) => key.CheckMe); checkMeOption.Change.Advise_HasNew(lifetime, v => { Text.Value = v.New ? "checked" : "not checked"; });

WPF Data Binding

Examples (?):

IProperty implements INotifyPropertyChanged out of the box, so, it is able to participate in WPF data binding. For example, we can show the current value of an IProperty on a WPF control. Let's take a look at how to do this based on the example from the previous section. Say, we want to display the value of the CheckMe setting (located in ReSharper | Options...). This is how the view model looks like:

public class OptionsPageViewModel: AAutomation { public IProperty<string> Text { get; set; } public OptionsPageViewModel(Lifetime lifetime, ISettingsStore settingsStore) { Text = new Property<string>(lifetime, "OptionsExampleViewModel.Text"); var checkMeOption = settingsStore.BindToContextLive(lifetime, ContextRange.ApplicationWide) .GetValueProperty(lifetime, (MySettingsKey key) => key.CheckMe); checkMeOption.Change.Advise_HasNew(lifetime, v => { Text.Value = v.New ? "checked" : "not checked"; }); } }

The code behind the view looks like follows:

[View] public partial class OptionsPageView : IView<OptionsPageViewModel> { public new string Name => "Options"; public OptionsPageView() { InitializeComponent(); } }

The XAML for the view:

<UserControl x:Class="SampleReSharperPlugin.OptionsPageView" ... xmlns:viewModels="clr-namespace:SampleReSharperPlugin" d:DataContext="{d:DesignInstance Type={x:Type viewModels:OptionsPageViewModel}, IsDesignTimeCreatable=False}"> <Grid> <StackPanel> <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Margin="10,10,5,0"> The option in <Bold>ReShaper > Options... > Tools > Sample R# Plugin > Sample bool option</Bold> is: <InlineUIContainer> <TextBlock TextWrapping="Wrap" Text="{Binding Text.Value}" FontWeight="Bold" /> </InlineUIContainer> </TextBlock> </StackPanel> </Grid> </UserControl>

When creating a view and viewmodel, don't forget to specify data context:

var propViewModel = new PropertyViewModel(lifetime); var propView = new PropertyView { DataContext = propViewModel };

Data Flow Between Properties

Examples (?):

You can organize the data flow between two properties. The properties can be of the same type or of different types. In the latter case, you should write a type converter. For example, we have two string properties: the first one provides some string; the second one takes this string and applies to it Title Capitalization:

public class PropertyFlow { public IProperty<string> SourceProperty { get; set; } public IProperty<string> TargetProperty { get; set; } public PropertyFlow(Lifetime lifetime) { SourceProperty = new Property<string>(lifetime, "sourceProperty"); TargetProperty = new Property<string>(lifetime, "targetProperty"); SourceProperty.FlowChangesInto(lifetime, TargetProperty, s => { if (string.IsNullOrEmpty(s)) return ""; var textInfo = new CultureInfo("en-US", false).TextInfo; s = textInfo.ToTitleCase(s); return s; }); } }

Color Themes

The classes responsible for working with color themes extensively use IProperty. For more details, refer to Work with Color Themes.

Last modified: 04 July 2023