Visual Studio SDKで設定ページを作る場合、Visual Studioのメニューのツール>オプション
に自分のカテゴリを追加することができます。この追加したカテゴリよく見ると、デフォルトっぽい画面と自前で作っているっぽい画面の二種類あることがわかります。
デフォルトの例
自前の例
デフォルトの設定ページの作り方はドキュメントがあるので、自前の画面の作り方を説明します。
オプション ページを作成する | Microsoft Docs
使うクラスはMicrosoft.VisualStudio.Shell.UIElementDialogPage
クラスです。このクラスの存在はこのブログを読んで知りました。実際にVS2017で使うにはいくつか足りないところがあったので補足しています。
これを継承した適当なクラスを作ります。
using Microsoft.VisualStudio.Shell; using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.Windows; namespace MyVisualStudio.Vsix.Options { [ClassInterface(ClassInterfaceType.AutoDual)] [Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")] //GUIDは適当な値 public sealed class MySetting : UIElementDialogPage { private readonly MyViewModel viewModel; private readonly MyView view; protected override UIElement Child => view; public OpenShiftMasterEndpointSetting() { viewModel = new MyViewModel(); view = new MyView { DataContext = viewModel }; } public override void LoadSettingsFromStorage() { //ここを同期的に完了を待ったほうがいいかどうかは謎 viewModel.LoadAsync().GetAwaiter().GetResult(); base.LoadSettingsFromStorage(); } protected override void OnClosed(EventArgs e) { //設定画面でキャンセルが押されたときなど。 //保存に失敗したとか、未保存状態のときにクローズをキャンセルする手はありそう base.OnClosed(e); } public override void SaveSettingsToStorage() { //保存処理 viewModel.SaveAsync().GetAwaiter().GetResult(); base.SaveSettingsToStorage(); } public override void ResetSettings() { base.ResetSettings(); } protected override void OnActivate(CancelEventArgs e) { //設定ダイアログで該当カテゴリに移動したとき base.OnActivate(e); } protected override void OnDeactivate(CancelEventArgs e) { //設定ダイアログで該当カテゴリから移動するとき base.OnDeactivate(e); } } }
Child
プロパティを継承して自前のユーザーコントロールのインスタンスを返すようにします。この例では、ViewModelもこのクラスが参照を持っていますが、その辺はお好きに。設定データの読み込みと保存はLoadSettingsFromStorage
とSaveSettingsToStorage
メソッドをオーバーライドして行います。なんとなく処理の完了を待機した方がいいのでしていますが、あまり自信はないです。
次にVisual Studio SDKプロジェクトを作ったときのPackageクラスの属性に次のように設定のカテゴリ、ページ名を追加します。
[ProvideOptionPage(typeof(MySetting ), "MySettingCategory", "MySettingPage", 0, 0, true)] public sealed class MyVSPackage : Package
あとは、適当にViewとViewModelを渡せばいいわけですが、保存処理についてです。自前で適当なところに保存してもいいのでしょうが、今回はMicrosoft.VisualStudio.Settings.WritableSettingsStore
クラスを使いました。最初に紹介したブログによるとVSIXをバージョンアップしても設定をきちんと保持できるとあるので、今度検証してみましょう。WritableSettingsStore
はいくつかのプリミティブなオブジェクトしか保存するメソッドを用意していないので、今回は安易にJSONに変換して保存いています。
using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Settings; using Newtonsoft.Json; using Reactive.Bindings; using System; using System.Diagnostics; using System.Linq; namespace MyVisualStudio.Vsix.Models { internal class SettingModel { const string CollectionPath = "MySetting"; const string PropertyName = "AllMySetting"; readonly WritableSettingsStore writableSettingsStore; internal SettingModel() { var shellSettingsManager = new ShellSettingsManager(ServiceProvider.GlobalProvider); writableSettingsStore = shellSettingsManager.GetWritableSettingsStore(SettingsScope.UserSettings); Load(); } internal void Load() { try { if (writableSettingsStore.PropertyExists(CollectionPath, PropertyName)) { var json = writableSettingsStore.GetString(CollectionPath, PropertyName); var entites = JsonConvert.DeserializeObject<MyEntity>(json); //entites を適当に渡す } } catch (Exception ex) { Debug.Fail(ex.Message); } } internal void Save() { try { if (!writableSettingsStore.CollectionExists(CollectionPath)) { writableSettingsStore.CreateCollection(CollectionPath); } //entitiesを適当にとってくる var jsonString = JsonConvert.SerializeObject(entites); writableSettingsStore.SetString(CollectionPath, PropertyName, jsonString); } catch (Exception ex) { Debug.Fail(ex.Message); } } } }