Walkthrough: Creating an Options Page
This walkthrough creates two Tools Options pages, a simple page and a custom page. The simple page uses a property grid to examine and set properties, and the custom page provides its own user interface (UI). The managed package framework (MPF) supports both scenarios, with very little additional code.
To save these properties to and restore them from a settings file, follow these steps, and then see Walkthrough: Creating a Settings Category.
The MPF provides two classes to help you create Tools Options pages, the Package class and the DialogPage class. You create a VSPackage to provide a container for these pages by subclassing the Package class. You create each tools options page by deriving from the DialogPage class.
In this walkthrough, you create the Tools Options pages and use them to display and change application options. You retrieve the option values from the hosting VSPackage. You retrieve them programmatically from another VSPackage by using Automation.
Prerequisites
To follow this walkthrough, you must install the Visual Studio 2013 SDK. For more information, see Visual Studio Software Development Kit (SDK).
Locations for the Visual Studio Package Project Template
The Visual Studio Package project template can be found in three different locations in the New Project dialog:
Under Visual Basic, Extensibility. The default language of the project is Visual Basic.
Under C#, Extensibility. The default language of the project is C#.
Under Other Project Types, Extensibility. The default language of the project is C++.
Creating a Tools Options Grid Page
In this section, you use the Visual Studio Package project template to create a simple Tools Options property grid. You use this grid to display and change the value of a property.
To create the VSPackage project
Create a Visual Studio Package project named MyToolsOptions in C# or Visual Basic.
For more information about how to create a managed VSPackage, see Walkthrough: Creating a Menu Command By Using the Visual Studio Package Template.
Add a menu command such that the Command name is Get Integer Option and the Command ID is cmdidGetIntOpt.
To create the Tools Options property grid
Open the MyToolsOptionsPackage file in the code editor.
Add the following namespace references.
Imports System.ComponentModel
using System.ComponentModel;
Declare an OptionPageGrid class and derive it from DialogPage.
Public Class OptionPageGrid Inherits DialogPage
public class OptionPageGrid : DialogPage
Apply a ClassInterfaceAttribute to the OptionPageGrid class:
<ClassInterface(ClassInterfaceType.AutoDual)> <CLSCompliant(False), ComVisible(True)> Public Class OptionPageGrid Inherits DialogPage
[ClassInterface(ClassInterfaceType.AutoDual)] [CLSCompliant(false), ComVisible(true)] public class OptionPageGrid : DialogPage
This creates a COM dual interface that lets Visual Studio Automation use GetAutomationObject to access the public members of the class programmatically.
Apply a ProvideOptionPageAttribute to the VSPackage class to assign to the class an options category and options page name for the OptionPageGrid.
<PackageRegistration(UseManagedResourcesOnly:=True), InstalledProductRegistration("#110", "#112", "1.0", IconResourceID:=400), ProvideMenuResource("Menus.ctmenu", 1), Guid(GuidList.guidMyToolsOptionsPkgString)> <ProvideOptionPage(GetType(OptionPageGrid), "My Category", "My Grid Page", 0, 0, True)> Public NotInheritable Class MyToolsOptionsPackage Inherits Package
[PackageRegistration(UseManagedResourcesOnly = true), InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400), ProvideMenuResource("Menus.ctmenu", 1), Guid(GuidList.guidMyToolsOptionsPkgString)] [ProvideOptionPage(typeof(OptionPageGrid), "My Category", "My Grid Page", 0, 0, true)] public sealed class MyToolsOptionsPackage : Package
Note
You can localize the category by assigning a resource ID to the attribute property CategoryResourceID.
Add an OptionInteger property to the OptionPageGrid class.
Apply a CategoryAttribute to assign to the property a property grid category.
Apply a DisplayNameAttribute to assign to the property a name.
Apply a DescriptionAttribute to assign to the property a description.
<ClassInterface(ClassInterfaceType.AutoDual)> <CLSCompliant(False), ComVisible(True)> Public Class OptionPageGrid Inherits DialogPage Private optionValue As Integer = 256 <Category("My Category")> <DisplayName("My Option Integer")> <Description("My integer option")> Public Property OptionInteger() As Integer Get Return optionValue End Get Set(ByVal value As Integer) optionValue = value End Set End Property End Class
[ClassInterface(ClassInterfaceType.AutoDual)] [CLSCompliant(false), ComVisible(true)] public class OptionPageGrid : DialogPage { private int optionValue = 256; [Category("My Category")] [DisplayName("My Integer Option")] [Description("My integer option")] public int OptionInteger { get { return optionValue; } set { optionValue = value; } } }
Note
The default implementation of DialogPage supports properties that have appropriate converters or that are structures or arrays that can be expanded into properties that have appropriate converters. For a list of converters, see the System.ComponentModel namespace. The Visual Studio Extensibility Samples manages int, string, and System.Drawing.Size properties.
Build the project and start debugging.
In the experimental instance of Visual Studio, on the Tools menu click Options.
In the left pane you should see My Category. (Options categories are listed in alphabetical order, so it should appear about halfway down the list.) Expand My Category and then click My Grid Page.The options grid appears in the right pane. The property category is My Options, and the property name is My Integer Option . The property description, My integer option, appears at the bottom of the pane. Change the value from its initial value of 256 to something else. Click OK, and then reopen My Grid Page. You can see that the new value persists.
Creating a Tools Options Custom Page
In this section, you create a Tools Options page with a custom UI. You use this page to display and change the value of a property.
To create a Tools Options custom page
Open the MyToolsOptionsPackage file in the code editor.
Add the following namespace statement.
Imports System.Windows.Forms
using System.Windows.Forms;
Add an OptionPageCustom class, just before the OptionPageGrid class. Derive the new class from DialogPage.
Public Class OptionPageCustom Inherits DialogPage
public class OptionPageCustom : DialogPage
Add the following attribute and GUID. Add an OptionString property:
<ClassInterface(ClassInterfaceType.AutoDual), Guid("42C7F4D9-200D-4fe2-A093-49AFA2DDE7F8")> Public Class OptionPageCustom Inherits DialogPage Private optionValue As String = "alpha" Public Property OptionString() As String Get Return optionValue End Get Set(ByVal value As String) optionValue = value End Set End Property End Class
[ClassInterface(ClassInterfaceType.AutoDual)] [Guid("1D9ECCF3-5D2F-4112-9B25-264596873DC9")] public class OptionPageCustom : DialogPage { private string optionValue = "alpha"; public string OptionString { get { return optionValue; } set { optionValue = value; } } }
Apply a ProvideOptionPageAttribute to the VSPackage class. This will assign the class an options category and options page name.
<PackageRegistration(UseManagedResourcesOnly:=True), InstalledProductRegistration("#110", "#112", "1.0", IconResourceID:=400), ProvideMenuResource("Menus.ctmenu", 1), Guid(GuidList.guidMyToolsOptionsPkgString)> <ProvideOptionPage(GetType(OptionPageCustom), "My Category", "My Custom Page", 0, 0, True)> <ProvideOptionPage(GetType(OptionPageGrid), "My Category", "My Grid Page", 0, 0, True)> Public NotInheritable Class MyToolsOptionsPackage Inherits Package
[PackageRegistration(UseManagedResourcesOnly = true), InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400), ProvideMenuResource("Menus.ctmenu", 1), Guid(GuidList.guidMyToolsOptionsPkgString)] [ProvideOptionPage(typeof(OptionPageCustom), "My Category", "My Custom Page", 0, 0, true)] [ProvideOptionPage(typeof(OptionPageGrid), "My Category", "My Grid Page", 0, 0, true)] public sealed class MyToolsOptionsPackage : Package
Add a user control named MyUserControl to the project.
The user control opens in Design view.
Note
If you see a warning, rebuild the solution and reopen the MyUserControl file. This is a known issue.
Add a TextBox control to the user control. In the Properties window, on the toolbar, click the Events button, and then double-click the Leave event.
The code editor opens to show the new event handler.
Add a public OptionsPage field, an Initialize method to the control class, and update the body of the event handler as follows:
Public Class MyUserControl Friend optionsPage As OptionPageCustom Public Sub Initialize() TextBox1.Text = optionsPage.OptionString End Sub Private Sub TextBox1_Leave(ByVal sender As Object, ByVal e As EventArgs) _ Handles TextBox1.Leave optionsPage.OptionString = TextBox1.Text End Sub End Class
public partial class MyUserControl : UserControl { public MyUserControl() { InitializeComponent(); } internal OptionPageCustom optionsPage; public void Initialize() { textBox1.Text = optionsPage.OptionString; } private void textBox1_Leave(object sender, EventArgs e) { optionsPage.OptionString = textBox1.Text; } }
The optionsPage field holds a reference to the parent OptionPageCustom instance. The Initialize method displays OptionString in the TextBox. The event handler writes the current value of the TextBox to the OptionString when focus leaves the TextBox.
In the package code file, add an override for the OptionPageCustom.Window property to the OptionPageCustom class to create, initialize, and return an instance of MyUserControl. Following is an example:
<Browsable(False)> <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> Protected Overrides ReadOnly Property Window() As IWin32Window Get Dim page As New MyUserControl() page.optionsPage = Me page.Initialize() Return page End Get End Property
[Browsable(false)] [DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden)] protected override IWin32Window Window { get { MyUserControl page = new MyUserControl(); page.optionsPage = this; page.Initialize(); return page; } }
Build and run the project.
In the experimental instance, click the Tools menu and then click Options.
The Options dialog opens.
In the tree view in the left pane, expand My Category and then click My Custom Page.
Change the value of OptionString from its initial value, alpha, to something else. Click OK, and then reopen My Custom Page. You can see that the new value has persisted.
Accessing Options from the Hosting VSPackage
In this section, you obtain the value of an option from the VSPackage that hosts the associated Tools Options page. The same technique can be used to obtain the value of any public property.
To access an option from the hosting VSPackage
In the package file, replace the body of the MyToolsOptions.MenuItemCallback method with the following lines:
Private Sub MenuItemCallback(ByVal sender As Object, ByVal e As EventArgs) Dim page As OptionPageGrid = CType(GetDialogPage(GetType(OptionPageGrid)), OptionPageGrid) MessageBox.Show(String.Format(CultureInfo.CurrentCulture, "OptionInteger: {0}", page.OptionInteger)) End Sub
private void MenuItemCallback(object sender, EventArgs e) { OptionPageGrid page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid)); MessageBox.Show(string.Format(CultureInfo.CurrentCulture, "OptionInteger: {0}", page.OptionInteger)); }
This code calls GetDialogPage to create or retrieve an OptionPageGrid instance. OptionPageGrid in turn invokes LoadSettingsFromStorage to load its options, which are public properties.
Build the project and start debugging.
In the experimental instance, on the Tools menu, click Get Integer Option.
A message box displays the current value of OptionInteger.
Accessing Options by using Automation
In this section, you use Automation to obtain the value of an option from any VSPackage or add-in. The same technique can be used to obtain the value of any public property.
To access an option using Automation
Right-click the MyToolsOptions solution in Solution Explorer and add a new VSPackage project named AnotherPackage.
Add a menu command Get external option.
Right-click the AnotherPackage project node and then click Set as StartUp Project.
Add the following namespace references to the AnotherPackagePackage code file:
Imports EnvDTE Imports System.Windows.Forms
using EnvDTE; using System.Windows.Forms;
Replace the body of the AnotherPackage.MenuItemCallback method with the following lines:
Private Sub MenuItemCallback(ByVal sender As Object, ByVal e As EventArgs) Dim env As DTE = CType(GetService(GetType(DTE)), DTE) Dim props As EnvDTE.Properties = env.Properties("My Category", "My Grid Page") Dim value As Integer = CInt(props.Item("OptionInteger").Value) MessageBox.Show("OptionInteger: " & value.ToString()) End Sub
private void MenuItemCallback(object sender, EventArgs e) { DTE env = (DTE)GetService(typeof(DTE)); EnvDTE.Properties props = env.get_Properties("My Category", "My Grid Page"); int n = (int)props.Item("OptionInteger").Value; MessageBox.Show("OptionInteger: " + n); }
This code calls a service to obtain the DTE object, the root object of the Visual Studio Automation model. Properties returns the properties collection for My Category.MyGridPage, which includes all public properties. The Item method selects OptionInteger from the collection.
Build the project and start debugging.
On the Tools menu, click Get external option.
A message box displays the current value of OptionInteger.