Plugin writers can use a wide variety of mechanisms in order to store and retrieve program settings. However, ReSharper provides its own infrastructure for keeping options. The advantages of this approach are that
- Special arrangements exist which let the settings interact cleanly with Options Pages
- A uniform API makes settings easier to use in your components
- The settings infrastructure is conducive to settings migration, overlays, and other interactions
Please note that this guide describes the settings model in ReSharper 6.1. As a result, the contents of this guide will be inapplicable for development of plug-ins for ReSharper 6.0 and earlier versions.
Using and Changing Settings
Defining a Settings Class
In ReSharper, settings are kept in ordinary classes that have been decorated with some metadata. Let us take a look at an example of a settings class:
As you can see, the above class is decorated with the
SettingsKey attribute. This attribute is used to provide some information about what settings are kept, as well as their type. In the above example, the type of the settings is internet-related, and is indicated as such. You can explore ReSharper to find potential settings categories or, if you can't find a suitable type, simply use
System.Reflection.Missing as the type.
SettingsKey attribute, each property in the class is decorated with the
SettingsEntry attribute. This attribute takes two parameters - the first being the default value for the property, the second the property's textual description.
Reading and Writing Settings
Rather than reading the settings directly, the correct approach is to bind settings to a particular context, and then operate on settings in this particular context. In order to bind settings, you first need an
ISettingsStore, which can be injected into the required component via the constructor. Once you have acquired the
ISettingsStore, you can bind it to a given data context (i.e., and
IDataContext) using code similar to the following:
Subsequently, you can use the
GetKey() method of
boundSettings to access the settings you need. For example:
Now, when it comes to writing settings, there is a corresponding
SetKey() method, but there is also a way to bind particular settings directly to UI (for example, when you are showing an options page). In order to do this, instead of injecting an
ISettingsStore, you need to inject a class called
OptionsSettingsSmartContext. This class has a
SetBinding method that takes the following parameters:
Lifetimeentity, which you can also inject into your options page.
- A reference to the UI control that needs to be bound. This is done differently for WPF and WinForms.
- A lambda in the form
(MySetting s) => s.SomePropertythat tells the smart context which property to bind.
For example, to bind
Username property to a WPF
usernameBox, you could write the following:
Things are a little different if you need to bind to a WinForms property: in thic case, you can use the
WinFormsProperty helper class, particularly its
A small note on data contexts: as you have seen, the
BindToContextTransient takes a data context as a parameter, which is fine if you’ve got an Action, but a bit more challenging if you need to read a value elsewhere. In this case, you can do the following:
- Inject a
DataContexts(note the -s at the end) value into your component.
dataContexts.Emptyas the parameter.
Working with Settings Layers
In addition to being able to manipulate settings individually, ReSharper also allows wholesale manipulation of settings using the concept of layers. A layer is simply a collection of settings that are stored in a particular file. The layering effect is such that layers above override the settings of layers below.
If you go into ReSharper | Manage Options… with an open solution, you will typically see three layers:
- A personal layer
- A team-shared layer
- A settings file stored on this computer
The sum total of settings is held in a registrar that can be affected using an API that is available to plugin writers. For example, if you have a separate settings file that you want to programmatically inject, you can use the
FileInjectedLayers shell component to inject this file using code similar to the following:
The above assumes that
context is an available
fileInjectedLayers is a shell component (acquired, e.g., by constructor injection) of type