Update samples for VS 17.11

---------

Co-authored-by: Matteo Prosperi <maprospe@microsoft.com>
Co-authored-by: Bertan Aygun <bertaygu@microsoft.com>
Co-authored-by: Jasmine Woon <jasminewoon@microsoft.com>
Co-authored-by: Jasmine Woon <jxwoon22@gmail.com>
This commit is contained in:
Matteo Prosperi 2024-08-13 16:40:13 -07:00 коммит произвёл GitHub
Родитель 3ecdf2a8a8
Коммит 23317634f0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
51 изменённых файлов: 467 добавлений и 127 удалений

Просмотреть файл

@ -11,7 +11,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
</Project>

Просмотреть файл

@ -11,8 +11,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.SDK" Version="17.6.36389" ExcludeAssets="runtime" />
</ItemGroup>

Просмотреть файл

@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -6,8 +6,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -32,10 +32,10 @@ public static class PathCapture
q => q.With(p => p.Path),
cancellationToken);
IProjectSnapshot result = queryResultsMainPath.FirstOrDefault()
string result = queryResultsMainPath.FirstOrDefault()?.Path
?? throw new ApplicationException("Project not found.");
return result.Path;
return result;
}
catch (Exception ex)
{
@ -50,8 +50,8 @@ public static class PathCapture
#pragma warning disable VSEXTPREVIEW_PROJECTQUERY_PROPERTIES_BUILDPROPERTIES // Type is for evaluation purposes only and is subject to change or removal in future updates.
IQueryResults<IProjectSnapshot> queryResults = await clientContext.Extensibility.Workspaces().QueryProjectsAsync(
project => project.With(p => p.ActiveConfigurations
.With(config => config.BuildPropertiesByName(
PersistenceStorageType.ProjectFile,
.With(config => config.PropertiesByName(
PropertySourceType.ProjectFile,
"TargetVsixContainer"))),
cancellationToken);
@ -61,7 +61,7 @@ public static class PathCapture
IProjectConfigurationSnapshot activeConfig = projectQueryResult.ActiveConfigurations.FirstOrDefault()
?? throw new InvalidOperationException("None active configurations.");
IBuildPropertySnapshot projectProperty = activeConfig.BuildProperties.FirstOrDefault()
IPropertySnapshot projectProperty = activeConfig.Properties.FirstOrDefault()
?? throw new InvalidOperationException("TargetVsixContainer not found.");
return projectProperty.Value!;

Просмотреть файл

@ -6,13 +6,14 @@
<NeutralLanguage>en-US</NeutralLanguage>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.LanguageServer.Protocol" Version="17.2.8" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="EditorMargin\WordCountControl.xaml" />
<EmbeddedResource Include="Image\ModalDialogControl.xaml" />
<EmbeddedResource Include="MainToolWindowControl.xaml" />
<EmbeddedResource Include="ModalDialog\ModalDialogControl.xaml" />
<EmbeddedResource Include="ModalDialog\XamlResources.*xaml" />
@ -20,5 +21,7 @@
<Page Remove="EditorMargin\WordCountControl.xaml" />
<Page Remove="ModalDialog\ModalDialogControl.xaml" />
<Page Remove="ModalDialog\XamlResources.*xaml" />
<None Remove="Images\DefaultText.16.16.png" />
<Page Remove="Image\ModalDialogControl.xaml" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if INPROC
namespace InProcFeatureGallery;
#else
namespace FeatureGallery;
#endif
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
[DataContract]
internal class ImageTest : TestData
{
public ImageTest(VisualStudioExtensibility extensibility)
: base(extensibility)
{
}
[DataMember]
public override string ButtonText => "Images";
[DataMember]
public override string Description => "This command opens a modal dialog showing 7 images in red borders.";
protected override async Task RunAsync(IClientContext clientContext, CancellationToken cancellationToken)
{
#pragma warning disable CA2000 // Dispose objects before losing scope. ModalDialogControl is passed to Visual Studio which will take care of disposing it
await this.Extensibility.Shell().ShowDialogAsync(new Image.ModalDialogControl(), cancellationToken);
#pragma warning restore CA2000 // Dispose objects before losing scope
}
}

Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if INPROC
namespace InProcFeatureGallery.Image;
#else
namespace FeatureGallery.Image;
#endif
using Microsoft.VisualStudio.Extensibility.UI;
/// <summary>
/// A sample remote user control to use as tool window UI content.
/// </summary>
internal class ModalDialogControl : RemoteUserControl
{
/// <summary>
/// Initializes a new instance of the <see cref="ModalDialogControl" /> class.
/// </summary>
public ModalDialogControl()
: base(new ModalDialogData())
{
}
}

Просмотреть файл

@ -0,0 +1,29 @@
<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">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Border BorderThickness="2" BorderBrush="Red" Margin="2">
<vs:Image Source="KnownMonikers.ClearWindowContent" />
</Border>
<Border BorderThickness="2" BorderBrush="Red" Margin="2">
<vs:Image Source="DefaultText" />
</Border>
<Border BorderThickness="2" BorderBrush="Red" Margin="2">
<vs:Image Source="{Binding StringImage}" />
</Border>
<Border BorderThickness="2" BorderBrush="Red" Margin="2">
<vs:Image Source="{Binding StringImageFromCatalog}" />
</Border>
<Border BorderThickness="2" BorderBrush="Red" Margin="2">
<vs:Image Source="{Binding StringImageId}" />
</Border>
<Border BorderThickness="2" BorderBrush="Red" Margin="2">
<vs:Image Source="{Binding MonikerImage}" />
</Border>
<Border BorderThickness="2" BorderBrush="Red" Margin="2">
<vs:Image Source="{Binding MonikerImageFromCatalog}" />
</Border>
</StackPanel>
</DataTemplate>

Просмотреть файл

@ -0,0 +1,33 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if INPROC
namespace InProcFeatureGallery.Image;
#else
namespace FeatureGallery.Image;
#endif
using System;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.UI;
[DataContract]
internal class ModalDialogData
{
[DataMember]
public string StringImage { get; } = "DefaultText";
[DataMember]
public string StringImageFromCatalog { get; } = "KnownMonikers.ClearWindowContent";
[DataMember]
public ImageMoniker StringImageId { get; } = "ae27a6b0-e345-4288-96df-5eaf394ee369;1935";
[DataMember]
public ImageMoniker MonikerImage { get; } = ImageMoniker.Custom("KnownMonikers.ClearWindowContent");
[DataMember]
public ImageMoniker MonikerImageFromCatalog { get; } = ImageMoniker.KnownValues.Import;
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 406 B

Просмотреть файл

@ -38,6 +38,8 @@ public class MainToolWindow : ToolWindow
new ModalDialogTest(this.Extensibility),
new EditorMarginTest(this.Extensibility),
new LanguageServerTest(this.Extensibility),
new SettingsTest(this.Extensibility),
new ImageTest(this.Extensibility),
};
}

Просмотреть файл

@ -0,0 +1,77 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#if INPROC
namespace InProcFeatureGallery;
#else
namespace FeatureGallery;
#endif
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Settings;
using Microsoft.VisualStudio.Extensibility.Shell;
[DataContract]
internal class SettingsTest : TestData
{
public SettingsTest(VisualStudioExtensibility extensibility)
: base(extensibility)
{
}
[DataMember]
public override string ButtonText => "Update a setting value";
[DataMember]
public override string Description => "This command updates a setting value and shows a prompt when the value update is complete.";
[VisualStudioContribution]
#pragma warning disable VSEXTPREVIEW_SETTINGS // Type is for evaluation purposes only and is subject to change or removal in future updates.
#pragma warning disable CEE0027 // String not localized
#if INPROC
private static SettingCategory Category { get; } = new("inProcFeatureGallery", "In-Proc Feature Gallery");
#else
private static SettingCategory Category { get; } = new("featureGallery", "Feature Gallery");
#endif
[VisualStudioContribution]
private static Setting.Boolean BooleanSetting { get; } = new("booleanSetting", "Boolean Setting", Category, defaultValue: false);
#pragma warning restore CEE0027 // String not localized
protected override async Task RunAsync(IClientContext clientContext, CancellationToken cancellationToken)
{
await this.Extensibility.Settings().WriteAsync(
batch => batch.WriteSetting(BooleanSetting, false),
"Setting booleanSetting to false",
cancellationToken);
await WaitForSettingValueAsync(expectedValue: false);
await this.Extensibility.Settings().WriteAsync(
batch => batch.WriteSetting(BooleanSetting, true),
"Setting booleanSetting to true",
cancellationToken);
await WaitForSettingValueAsync(expectedValue: true);
async Task WaitForSettingValueAsync(bool expectedValue)
{
TaskCompletionSource<bool> settingValueIsFalse = new();
using var settingValueObserver = await this.Extensibility.Settings().SubscribeAsync(BooleanSetting, cancellationToken, value =>
{
if (value.Succeeded && value.Value == expectedValue)
{
settingValueIsFalse.SetResult(true);
}
});
await settingValueIsFalse.Task;
}
await this.Extensibility.Shell().ShowPromptAsync("All done.", PromptOptions.OK, cancellationToken);
}
#pragma warning restore VSEXTPREVIEW_SETTINGS // Type is for evaluation purposes only and is subject to change or removal in future updates.
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 406 B

Просмотреть файл

@ -10,8 +10,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.LanguageServer.Protocol" Version="17.2.8" />
</ItemGroup>
@ -20,6 +20,7 @@
<EmbeddedResource Include="..\FeatureGallery\EditorMargin\WordCountControl.xaml" Link="EditorMargin\WordCountControl.xaml" />
<EmbeddedResource Include="..\FeatureGallery\ModalDialog\ModalDialogControl.xaml" Link="ModalDialog\ModalDialogControl.xaml" />
<EmbeddedResource Include="..\FeatureGallery\ModalDialog\XamlResources.*xaml" Link="ModalDialog\%(FileName)%(Extension)" />
<EmbeddedResource Include="..\FeatureGallery\Image\ModalDialogControl.xaml" Link="Image\ModalDialogControl.xaml" />
</ItemGroup>
<ItemGroup>
@ -27,6 +28,6 @@
</ItemGroup>
<ItemGroup>
<Content Include=".vsextension\string-resources.json" />
<None Remove="Images\DefaultText.16.16.png" />
</ItemGroup>
</Project>

Просмотреть файл

@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -9,8 +9,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup Condition="Exists('.\rust-analyzer.exe')">

Просмотреть файл

@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,3 +1,5 @@
{
"ToolWindowSample.MyToolWindowCommand.DisplayName": "My Tool Window"
"ToolWindowSample.MyToolWindowCommand.DisplayName": "My Tool Window",
"ToolWindowSample.MyToolbarCommand.DisplayName": "Toolbar command",
"ToolWindowSample.MyToolWindow.Toolbar.DisplayName": "My Toolbar"
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 564 B

Просмотреть файл

@ -6,6 +6,7 @@ namespace ToolWindowSample;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Commands;
using Microsoft.VisualStudio.Extensibility.ToolWindows;
using Microsoft.VisualStudio.RpcContracts.RemoteUI;
@ -29,6 +30,13 @@ public class MyToolWindow : ToolWindow
public override ToolWindowConfiguration ToolWindowConfiguration => new()
{
Placement = ToolWindowPlacement.DocumentWell,
Toolbar = new ToolWindowToolbar(Toolbar),
};
[VisualStudioContribution]
private static ToolbarConfiguration Toolbar => new("%ToolWindowSample.MyToolWindow.Toolbar.DisplayName%")
{
Children = [ToolbarChild.Command<MyToolbarCommand>()],
};
/// <inheritdoc />

Просмотреть файл

@ -18,7 +18,22 @@
HorizontalContentAlignment="Left"
VerticalContentAlignment="Center"
Text="{Binding Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource {x:Static styles:VsResourceKeys.TextBoxStyleKey}}" />
Style="{StaticResource {x:Static styles:VsResourceKeys.TextBoxStyleKey}}">
<TextBox.ContextMenu>
<ContextMenu Style="{DynamicResource {x:Static styles:VsResourceKeys.ContextMenuStyleKey}}">
<MenuItem Header="Clear" Command="{Binding ClearCommand}">
<MenuItem.Icon>
<vs:Image Source="KnownMonikers.ClearWindowContent" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Default message" Command="{Binding DefaultTextCommand}">
<MenuItem.Icon>
<vs:Image Source="DefaultText" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
<Button x:Name="ShowMessageButton"
Content="Show Dialog"
IsEnabled="False"

Просмотреть файл

@ -32,6 +32,8 @@ internal class MyToolWindowData : NotifyPropertyChangedObject
this.extensibility = Requires.NotNull(extensibility, nameof(extensibility));
this.ShowMessageCommand = new AsyncCommand(this.ShowMessageAsync);
this.ClearCommand = new AsyncCommand(this.ClearAsync);
this.DefaultTextCommand = new AsyncCommand(this.DefaultTextAsync);
}
/// <summary>
@ -43,6 +45,24 @@ internal class MyToolWindowData : NotifyPropertyChangedObject
get;
}
/// <summary>
/// Gets the async command used to clear the message text box.
/// </summary>
[DataMember]
public IAsyncCommand ClearCommand
{
get;
}
/// <summary>
/// Gets the async command used to set the message to a default value.
/// </summary>
[DataMember]
public IAsyncCommand DefaultTextCommand
{
get;
}
/// <summary>
/// Gets or sets a value indicating whether there is an error in the data context.
/// </summary>
@ -79,4 +99,16 @@ internal class MyToolWindowData : NotifyPropertyChangedObject
{
await this.extensibility.Shell().ShowPromptAsync(this.Message, PromptOptions.OK, cancellationToken);
}
private Task ClearAsync(object? commandParameter, CancellationToken cancellationToken)
{
this.Message = string.Empty;
return Task.CompletedTask;
}
private Task DefaultTextAsync(object? commandParameter, CancellationToken cancellationToken)
{
this.Message = "Hello world";
return Task.CompletedTask;
}
}

Просмотреть файл

@ -0,0 +1,29 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace ToolWindowSample;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Commands;
using Microsoft.VisualStudio.Extensibility.Shell;
/// <summary>
/// A sample command for showing a tool window.
/// </summary>
[VisualStudioContribution]
public class MyToolbarCommand : Command
{
/// <inheritdoc />
public override CommandConfiguration CommandConfiguration => new("%ToolWindowSample.MyToolbarCommand.DisplayName%")
{
Icon = new(ImageMoniker.KnownValues.Extension, IconSettings.IconOnly),
};
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
await this.Extensibility.Shell().ShowPromptAsync("The toolbar button was clicked", PromptOptions.OK, cancellationToken);
}
}

Просмотреть файл

@ -21,10 +21,10 @@ 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:
```csharp
public override ToolWindowConfiguration ToolWindowConfiguration => new()
{
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](https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.extensibility.toolwindows.toolwindowplacement?view=vs-extensibility) 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](https://learn.microsoft.com/en-us/visualstudio/extensibility/visualstudio.extensibility/tool-window/tool-window#toolwindow-attribute) to learn more about the configuration options.
@ -32,26 +32,25 @@ This configuration places the tool window in the document well when it's created
The title of the tool window can be customized by setting the Title property:
```csharp
public MyToolWindow(VisualStudioExtensibility extensibility)
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:
```csharp
public override Task InitializeAsync(CancellationToken cancellationToken)
{
public override Task InitializeAsync(CancellationToken cancellationToken)
{
this.dataContext = new MyToolWindowData(this.Extensibility);
return Task.CompletedTask;
}
public override Task<IRemoteUserControl> GetContentAsync(CancellationToken cancellationToken)
{
}
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.
@ -101,24 +100,48 @@ public class MyToolWindowCommand : Command
The `CommandConfiguration` property defines information about the command that are available to Visual Studio even before the extension is loaded:
```csharp
public override CommandConfiguration CommandConfiguration => new("%ToolWindowSample.MyToolWindowCommand.DisplayName%")
{
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.
```csharp
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
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.
## Adding a toolbar
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.
```csharp
[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:
```csharp
public override ToolWindowConfiguration ToolWindowConfiguration => new()
{
Placement = ToolWindowPlacement.DocumentWell,
Toolbar = new ToolWindowToolbar(Toolbar),
};
```
## Logging errors
Each extension part including command sets is assigned a `TraceSource` instance that can be utilized to log diagnostic errors. Please see [Logging](https://learn.microsoft.com/visualstudio/extensibility/visualstudio.extensibility/inside-the-sdk/logging) section for more information.

Просмотреть файл

@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
</Project>

Просмотреть файл

@ -24,7 +24,9 @@ public class AddFileCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
await this.Extensibility.Workspaces().UpdateProjectsAsync(
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
await querySpace.UpdateProjectsAsync(
project => project.Where(project => project.Name == "ConsoleApp1"),
project => project.AddFile("CreatedFile.txt"),
cancellationToken);

Просмотреть файл

@ -26,9 +26,10 @@ public class AddSolutionConfigurationCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
const string solutionName = "ConsoleApp32";
await this.Extensibility.Workspaces().UpdateSolutionAsync(
await querySpace.UpdateSolutionAsync(
solution => solution.Where(solution => solution.BaseName == solutionName),
solution => solution.AddSolutionConfiguration("Foo", "Debug", false),
cancellationToken);

Просмотреть файл

@ -26,9 +26,10 @@ public class DeleteSolutionConfigurationCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
const string solutionName = "ConsoleApp32";
await this.Extensibility.Workspaces().UpdateSolutionAsync(
await querySpace.UpdateSolutionAsync(
solution => solution.Where(solution => solution.BaseName == solutionName),
solution => solution.DeleteSolutionConfiguration("Foo"),
cancellationToken);

Просмотреть файл

@ -24,9 +24,10 @@ public class ProjectBuildCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
const string projectName = "ConsoleApp1";
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
var result = await querySpace.QueryProjectsAsync(
project => project.Where(p => p.Name == projectName),
cancellationToken);

Просмотреть файл

@ -26,7 +26,9 @@ public class QueryFileCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
var result = await querySpace.QueryProjectsAsync(
project => project.With(project => project.Name)
.With(project => project.Path)
.With(project => project.Files.With(file => file.FileName)),

Просмотреть файл

@ -26,9 +26,11 @@ public class QueryOutputGroupByIdCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
StringBuilder message = new StringBuilder();
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
var result = await querySpace.QueryProjectsAsync(
project => project.With(p => p.Name)
.With(p => p.ActiveConfigurations.With(c => c.Name)),
cancellationToken);

Просмотреть файл

@ -26,7 +26,9 @@ public class QueryOutputGroupByNameCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
var result = await querySpace.QueryProjectsAsync(
project => project.With(p => p.Name)
.With(p => p.ActiveConfigurations
.With(c => c.Name)

Просмотреть файл

@ -26,7 +26,9 @@ public class QueryOutputGroupByProjectCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
var result = await querySpace.QueryProjectsAsync(
project => project.With(p => p.Name)
.With(p => p.ActiveConfigurations
.With(c => c.Name)

Просмотреть файл

@ -26,7 +26,9 @@ public class QuerySolutionConfigurations : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
var results = await this.Extensibility.Workspaces().QuerySolutionAsync(
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
var results = await querySpace.QuerySolutionAsync(
solution => solution.With(solution => solution.SolutionConfigurations
.With(c => c.Name)),
cancellationToken);

Просмотреть файл

@ -1,7 +1,7 @@
---
title: VS Project Query API Extension reference
description: A reference for VS Project Query API Extension reference
date: 2024-1-11
date: 2024-6-24
---
# Walkthrough: VS Project Query API Extension
@ -16,7 +16,7 @@ The Project System Query API allows you to retrieve and update information in th
Add `Microsoft.VisualStudio.ProjectSystem.Query` NuGet Package to the solution's `references` to get access to the API.
The code snippet as seen below sets up the Project Query Service for the project:
The code snippet as seen below sets up the Project Query Service:
```csharp
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
@ -29,7 +29,7 @@ Once a `querySpace` is established, you may query information about the Project
In our example, we call the `QueryProjectsAsync` method to get information from the projects, namely the Project Name, Project Path, Project Files, and File Names.
```csharp
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
var result = await querySpace.QueryProjectsAsync(
project => project.With(project => project.Name)
.With(project => project.Path)
.With(project => project.Files.With(file => file.FileName)),
@ -43,7 +43,7 @@ Using the same `querySpace`, you may modify data in your project system. `Where`
In our example, we call the `UpdateProjectsAsync` method to create a new file. The file we want to add is called `CreatedFile.txt`, and we want to add it to our project called `ConsoleApp1`.
```csharp
await this.Extensibility.Workspaces().UpdateProjectsAsync(
await querySpace.UpdateProjectsAsync(
project => project.Where(project => project.Name == "ConsoleApp1"),
project => project.AddFile("CreatedFile.txt"),
cancellationToken);
@ -63,7 +63,7 @@ You may filter out metadata By Project in your solution.
In the snippet below, the result will contain information about Output Groups' names about all projects in our Solution.
```csharp
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
var result = await querySpace.QueryProjectsAsync(
project => project.With(p => p.Name)
.With(p => p.ActiveConfigurations
.With(c => c.Name)
@ -78,7 +78,7 @@ If you know which metadata you would like to obtain, you may filter that informa
In the snippet below, we call `OutputGroupsByName` to get specific Output Groups. The Project System Query API will add valid output group to the results, and invalid groups are skipped over. In this case, results will contain three output groups: `Built`, `XmlSerializer`, and `SourceFiles`.
```csharp
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
var result = await querySpace.QueryProjectsAsync(
project => project.With(p => p.Name)
.With(p => p.ActiveConfigurations
.With(c => c.Name)
@ -94,7 +94,7 @@ As usages for project query becomes more complex, you may realize that the requi
In our example, let's say we already queried information about Output Groups.
```csharp
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
var result = await querySpace.QueryProjectsAsync(
project => project.With(p => p.Name)
.With(p => p.ActiveConfigurations.With(c => c.Name)),
cancellationToken);
@ -144,7 +144,7 @@ var result = await querySpace.Solutions
In the snippet below, we specify the solution we would like to unload the project from and pass in the project path when we make our `UnloadProject` call.
```csharp
await this.Extensibility.Workspaces().UpdateSolutionAsync(
await querySpace.UpdateSolutionAsync(
solution => solution.Where(solution => solution.BaseName == solutionName),
solution => solution.UnloadProject(projectPath),
cancellationToken);
@ -153,7 +153,7 @@ await this.Extensibility.Workspaces().UpdateSolutionAsync(
Similarly, we can load the project by calling the `ReloadProject` API.
```csharp
await this.Extensibility.Workspaces().UpdateSolutionAsync(
await querySpace.UpdateSolutionAsync(
solution => solution.Where(solution => solution.BaseName == solutionName),
solution => solution.ReloadProject(projectPath),
cancellationToken);
@ -174,7 +174,7 @@ var result = await querySpace.Solutions.SaveAsync(cancellationToken);
Using the Project Query API, you also can select which projects get executed. In the sample below, we added two project paths to be set as the startup project.
```csharp
await this.Extensibility.Workspaces().UpdateSolutionAsync(
await querySpace.UpdateSolutionAsync(
solution => solution.Where(solution => solution.BaseName == solutionName),
solution => solution.SetStartupProjects(projectPath1, projectPath2),
cancellationToken);
@ -185,7 +185,7 @@ await this.Extensibility.Workspaces().UpdateSolutionAsync(
`AddSolutionConfiguration` is an API call that takes in three parameters. The first parameter is the new name we want to give our new solution configuration. In this scenario, we will call our new solution configuration `Foo`. The next parameter is the configuration to base our new configuration. Below, we based our new solution configuration on the existing solution configuration, `Debug`. Lastly, the boolean represents if the solution configuration should be propagated.
```csharp
await this.Extensibility.Workspaces().UpdateSolutionAsync(
await querySpace.UpdateSolutionAsync(
solution => solution.Where(solution => solution.BaseName == solutionName),
solution => solution.AddSolutionConfiguration("Foo", "Debug", false),
cancellationToken);
@ -194,7 +194,7 @@ await this.Extensibility.Workspaces().UpdateSolutionAsync(
`DeleteSolutionConfiguration` is an API call that removes the solution configuration. In the example below, we removed the solution configuration called `Foo`.
```csharp
await this.Extensibility.Workspaces().UpdateSolutionAsync(
await querySpace.UpdateSolutionAsync(
solution => solution.Where(solution => solution.BaseName == solutionName),
solution => solution.DeleteSolutionConfiguration("Foo"),
cancellationToken);
@ -229,15 +229,15 @@ var result = await querySpace.Projects
In the code sample, we will query the projects in a solution and skip the first one. Let's say there are 3 projects in the solution. The first result will be skipped and will return the two remaining projects. Note: the order is not guaranteed.
```csharp
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
project => project.With(p => p.Name
.Skip(1)),
var result = await querySpace.QueryProjectsAsync(
project => project.With(p => p.Name)
.Skip(1),
cancellationToken);
```
### Tracking Queries
In the example, `TrackUpdatesAsync` is called on the Files property of a project, with a file name filter applied. This means it will track changes to the file names in the project. The TrackerObserver instance is passed to receive notifications of changes.
In the example, `TrackUpdatesAsync` is called on the Files property of a project. The TrackerObserver instance is passed to receive notifications of changes.
```csharp
var unsubscriber = await singleProject

Просмотреть файл

@ -24,10 +24,12 @@ public class ReloadProjectCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
const string solutionName = "ConsoleApp32";
const string projectPath = "ConsoleApp1\\\\ConsoleApp1.csproj";
await this.Extensibility.Workspaces().UpdateSolutionAsync(
await querySpace.UpdateSolutionAsync(
solution => solution.Where(solution => solution.BaseName == solutionName),
solution => solution.ReloadProject(projectPath),
cancellationToken);

Просмотреть файл

@ -24,11 +24,13 @@ public class SetStartupProjectsCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
const string solutionName = "ConsoleApp32";
const string projectPath1 = "ConsoleApp1\\\\ConsoleApp1.csproj";
const string projectPath2 = "ConsoleApp2\\\\ConsoleApp2.csproj";
await this.Extensibility.Workspaces().UpdateSolutionAsync(
await querySpace.UpdateSolutionAsync(
solution => solution.Where(solution => solution.BaseName == solutionName),
solution => solution.SetStartupProjects(projectPath1, projectPath2),
cancellationToken);

Просмотреть файл

@ -51,9 +51,11 @@ namespace VSProjectQueryAPISample
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
var result = await this.Extensibility.Workspaces().QueryProjectsAsync(
project => project.With(p => p.Name
.Skip(1)),
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
var result = await querySpace.QueryProjectsAsync(
project => project.With(p => p.Name)
.Skip(1),
cancellationToken);
StringBuilder message = new StringBuilder($"\n \n === Skipping one === \n");

Просмотреть файл

@ -3,6 +3,7 @@
namespace VSProjectQueryAPISample;
using Microsoft.ServiceHub.Framework;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Commands;
using Microsoft.VisualStudio.Extensibility.Shell;
@ -24,7 +25,7 @@ public class SolutionBuildCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
var serviceBroker = context.Extensibility.ServiceBroker;
IServiceBroker serviceBroker = context.Extensibility.ServiceBroker;
ProjectQueryableSpace querySpace = new ProjectQueryableSpace(serviceBroker: serviceBroker, joinableTaskContext: null);
var result = await querySpace.Solutions
.BuildAsync(cancellationToken);

Просмотреть файл

@ -3,6 +3,7 @@
namespace VSProjectQueryAPISample;
using Microsoft.ServiceHub.Framework;
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.Commands;
using Microsoft.VisualStudio.Extensibility.Shell;
@ -24,7 +25,7 @@ public class SolutionSaveCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
var serviceBroker = context.Extensibility.ServiceBroker;
IServiceBroker serviceBroker = context.Extensibility.ServiceBroker;
ProjectQueryableSpace querySpace = new ProjectQueryableSpace(serviceBroker: serviceBroker, joinableTaskContext: null);
var result = await querySpace.Solutions.SaveAsync(cancellationToken);

Просмотреть файл

@ -50,7 +50,9 @@ namespace VSProjectQueryAPISample
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
var projects = await this.Extensibility.Workspaces().QueryProjectsAsync(
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
var projects = await querySpace.QueryProjectsAsync(
project => project.With(project => project.Name),
cancellationToken);

Просмотреть файл

@ -24,10 +24,12 @@ public class UnloadProjectCommand : Command
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
WorkspacesExtensibility querySpace = this.Extensibility.Workspaces();
const string solutionName = "ConsoleApp32";
const string projectPath = "ConsoleApp1\\\\ConsoleApp1.csproj";
await this.Extensibility.Workspaces().UpdateSolutionAsync(
await querySpace.UpdateSolutionAsync(
solution => solution.Where(solution => solution.BaseName == solutionName),
solution => solution.UnloadProject(projectPath),
cancellationToken);

Просмотреть файл

@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
</Project>

Просмотреть файл

@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.10.2084" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.11.40261" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.11.40261" />
</ItemGroup>
<ItemGroup>