I wanted to create a small extension to add a list of External Tools to VS2019. A quick search brought up what appeared to be perfect example code at https://learn.microsoft.com/en-us/visualstudio/extensibility/writing-to-the-user-settings-store?view=vs-2019. This adds a command to invoke Notepad, so I thought with a few edits, my work was done.
However, this example is written as a synchronous extension, which is deprecated, so I tried putting the code intended for MenuItemCallBack into the Execute method of the extension, but the line
SettingsManager settingsManager = new ShellSettingsManager(ServiceProvider);
fails to compile, because ServiceProvider is now type IAsyncServiceProvider and the ShellSettingsManager constructor wants an argument of type IServiceProvider.
As far as I can tell, ShellSettingsManager is still the way to access the Settings Store, but all the examples I could find all refer to putting code in MenuItemCallback (as well as being several years old) so are for synchronous extensions.
So, can someone point me to the recommended way to get access to the settings store in an asynchronous extension?
The ShellSettingsManager constructor takes either an IServiceProvider interface or an IVsSettings interface. Given your AsyncPackage derived object implements IServiceProvider, you should be able to just pass it in as the argument to your constructor. The following quick demo package worked for me:
using System;
using System.ComponentModel.Design;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.Settings;
using Task = System.Threading.Tasks.Task;
namespace UserSettingsDemo
{
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
[Guid(UserSettingsDemoPackage.PackageGuidString)]
[ProvideMenuResource("Menus.ctmenu", 1)]
public sealed class UserSettingsDemoPackage : AsyncPackage
{
public const string PackageGuidString = "cff6cdea-21d1-4736-b5ea-6736624e718f";
public static readonly Guid CommandSet = new Guid("dde1417d-ae0d-46c4-8c84-31883dc1a835");
public const int ListExternalToolsCommand = 0x0100;
protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
{
await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
OleMenuCommandService commandService = await GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
Assumes.Present(commandService);
var menuItem = new MenuCommand(OnListExternalTools, new CommandID(CommandSet, ListExternalToolsCommand));
commandService.AddCommand(menuItem);
}
private void OnListExternalTools(object sender, EventArgs e)
{
ShellSettingsManager settingsManager = new ShellSettingsManager(this);
WritableSettingsStore userSettingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);
int toolCount = userSettingsStore.GetInt32("External Tools", "ToolNumKeys");
for (int i = 0; i < toolCount; i++)
{
string tool = userSettingsStore.GetString("External Tools", "ToolCmd" + i);
VsShellUtilities.ShowMessageBox(this, tool, "External Tools", OLEMSGICON.OLEMSGICON_INFO,
OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
}
}
}
}
Sincerely