title | description | date |
---|---|---|
Tool Window Extension Sample reference |
A reference for Tool Window sample |
2023-10-24 |
This extension is a simple extension that shows how a tool window can be quickly added to Visual Studio.
The extension contains a code file that defines a tool window and its properties starting with the VisualStudioContribution
class attribute which makes the tool window available to Visual Studio:
[VisualStudioContribution]
public class MyToolWindow : ToolWindow
{
The ToolWindowConfiguration
property defines information about the tool window that is available to Visual Studio even before the extension is loaded:
public override ToolWindowConfiguration ToolWindowConfiguration => new()
{
Placement = ToolWindowPlacement.DocumentWell,
};
This configuration places the tool window in the document well when it's created the first time. You can refer to ToolWindowPlacement to learn about other placement options. Since this configuration doesn't specify the additional options, it will have the default DockDirection and AllowAutoCreation values. You can refer to ToolWindowConfiguration to learn more about the configuration options.
The title of the tool window can be customized by setting the Title property:
public MyToolWindow(VisualStudioExtensibility extensibility)
: base(extensibility)
{
this.Title = "My Tool Window";
}
Adding content to the tool window can be done by setting up a remote user control and corresponding data model:
public override Task InitializeAsync(CancellationToken cancellationToken)
{
this.dataContext = new MyToolWindowData(this.Extensibility);
return Task.CompletedTask;
}
public override Task<IRemoteUserControl> GetContentAsync(CancellationToken cancellationToken)
{
return Task.FromResult<IRemoteUserControl>(new MyToolWindowControl(this.dataContext));
}
The data model creation and any other precursor work should be done in the InitializeAsync while the actual UI creation happens in the GetContentAsync.
The tool window content is created as a DataTemplate .xaml file and a separate control class .cs file:
<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vs="http://schemas.microsoft.com/visualstudio/extensibility/2022/xaml"
xmlns:styles="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0"
xmlns:colors="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.15.0">
...
</DataTemplate>
internal class MyToolWindowControl : RemoteUserControl
{
The .cs and .xaml files should have the same name (MyToolWindowControl in this sample). Additionally the xaml file should be included as an EmbeddedResource instead of a Page, so editing the csproj file may be necessary in some cases.
A data model that backs the UI is required for data-driven UI:
[DataContract]
internal class MyToolWindowData : NotifyPropertyChangedObject
{
The data model must derive from NotifyPropertyChangedObject and set the DataContract class attribute and DataMemeber property attribute for all UI bound properties.
You can refer to Add content to a tool window to learn more about setting up the tool window content and remote UI.
Once the tool window is defined, it's common to have a command to allow showing the tool window. The extension contains a code file that defines a command and its properties starting with the VisualStudioContribution
class attribute which makes the command available to Visual Studio:
[VisualStudioContribution]
public class MyToolWindowCommand : Command
{
The CommandConfiguration
property defines information about the command that are available to Visual Studio even before the extension is loaded:
public override CommandConfiguration CommandConfiguration => new("%ToolWindowSample.MyToolWindowCommand.DisplayName%")
{
Placements = [CommandPlacement.KnownPlacements.ToolsMenu],
Icon = new(ImageMoniker.KnownValues.ToolWindow, IconSettings.IconAndText),
};
The command is placed in the Tools
top menu and uses the ToolWindow
icon moniker.
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
await this.Extensibility.Shell().ShowToolWindowAsync<MyToolWindow>(activate: true, cancellationToken);
}
When executed, the command will use the tool window type to look up and show that tool window. Because the parameter 'activate' is true, the tool window content will be focused when the tool window is shown. Passing 'false' instead means the tool window and its content will be shown, but not receive focus.
It is possible to add a toolbar to a tool window by contributing a toolbar configuration. The toolbar configuration is a static property that can be placed in any class of the project, but it is reasonable to add it to the MyToolWindow
class.
[VisualStudioContribution]
private static ToolbarConfiguration Toolbar => new("%ToolWindowSample.MyToolWindow.Toolbar.DisplayName%")
{
Children = [ToolbarChild.Command<MyToolbarCommand>()],
};
In the sample above, the toolbar contains a single command: MyToolbarCommand
.
Then we reference the toolbar from the tool window configuration:
public override ToolWindowConfiguration ToolWindowConfiguration => new()
{
Placement = ToolWindowPlacement.DocumentWell,
Toolbar = new ToolWindowToolbar(Toolbar),
};
Each extension part including command sets is assigned a TraceSource
instance that can be utilized to log diagnostic errors. Please see Logging section for more information.
Once deployed, the My Tool Window command can be used to show My Tool Window in the document well.