Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Utwórz okno narzędzi z możliwością dokowania przy użyciu interfejsu użytkownika powiązanego z danymi przy użyciu interfejsu użytkownika zdalnego i zestawu VisualStudio.Extensibility SDK.
Note
W tym przewodniku użyto zestawu VisualStudio.Extensibility SDK. Zobacz Wybierz odpowiedni model rozszerzalności, aby porównać modele.
Pełny przykład
Kompletna implementacja:
Definicja okna narzędziowego:
// 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.ToolWindows;
using Microsoft.VisualStudio.RpcContracts.RemoteUI;
/// <summary>
/// A sample tool window.
/// </summary>
[VisualStudioContribution]
public class MyToolWindow : ToolWindow
{
private object? dataContext;
/// <summary>
/// Initializes a new instance of the <see cref="MyToolWindow" /> class.
/// </summary>
public MyToolWindow()
{
this.Title = "My Tool Window";
}
/// <inheritdoc />
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 />
public override Task InitializeAsync(CancellationToken cancellationToken)
{
this.dataContext = new MyToolWindowData(this.Extensibility);
return Task.CompletedTask;
}
/// <inheritdoc />
public override Task<IRemoteUserControl> GetContentAsync(CancellationToken cancellationToken)
{
return Task.FromResult<IRemoteUserControl>(new MyToolWindowControl(this.dataContext));
}
}
Polecenie otwierające okno narzędzi:
// 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;
/// <summary>
/// A sample command for showing a tool window.
/// </summary>
[VisualStudioContribution]
public class MyToolWindowCommand : Command
{
/// <inheritdoc />
public override CommandConfiguration CommandConfiguration => new("%ToolWindowSample.MyToolWindowCommand.DisplayName%")
{
Placements = [CommandPlacement.KnownPlacements.ToolsMenu],
Icon = new(ImageMoniker.KnownValues.ToolWindow, IconSettings.IconAndText),
};
/// <inheritdoc />
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
await this.Extensibility.Shell().ShowToolWindowAsync<MyToolWindow>(activate: true, cancellationToken);
}
}
Tip
Zobacz kompletny działający przykład: ToolWindowSample ↗
Powiązane pojęcia:Zdalny interfejs użytkownika — model powiązania danych używany na potrzeby zawartości okna narzędzi, Wkłady i konfiguracje — jak deklarowane są wkłady do okien narzędzi
Zrozum przykład
Krok 1: Zdefiniuj klasę okna narzędzia
Rozszerz ToolWindow i oznacz go za pomocą polecenia [VisualStudioContribution]:
[VisualStudioContribution]
internal class MyToolWindow : ToolWindow
{
private MyDataModel? dataModel;
public MyToolWindow(VisualStudioExtensibility extensibility)
: base(extensibility)
{
Title = "My Tool Window";
}
public override ToolWindowConfiguration ToolWindowConfiguration => new()
{
Placement = ToolWindowPlacement.DocumentWell,
AllowAutoCreation = true,
};
public override async Task InitializeAsync(CancellationToken cancellationToken)
{
dataModel = new MyDataModel();
await dataModel.LoadAsync(cancellationToken);
}
public override Task<IRemoteUserControl> GetContentAsync(CancellationToken cancellationToken)
{
return Task.FromResult<IRemoteUserControl>(new MyToolWindowControl(dataModel!));
}
}
Krok 2: Utwórz model danych
Użyj NotifyPropertyChangedObject z [DataMember] i [DataContract] do powiązania danych zdalnego interfejsu użytkownika:
[DataContract]
internal class MyDataModel : NotifyPropertyChangedObject
{
private string message = "Hello from the tool window!";
[DataMember]
public string Message
{
get => message;
set => SetProperty(ref message, value);
}
public async Task LoadAsync(CancellationToken cancellationToken)
{
// Load data asynchronously
}
}
Krok 3: Tworzenie kontrolki Remote UI
Dodaj klasę RemoteUserControl i pasujący szablon danych XAML.
MyToolWindowControl.cs:
internal class MyToolWindowControl : RemoteUserControl
{
public MyToolWindowControl(MyDataModel dataModel)
: base(dataContext: dataModel)
{
}
}
MyToolWindowControl.xaml — ustaw akcję kompilacji na EmbeddedResource (a nie Page):
<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">
<StackPanel Margin="10">
<TextBlock Text="{Binding Message}" FontSize="14" />
</StackPanel>
</DataTemplate>
Important
Plik XAML musi używać akcji kompilacji EmbeddedResource . Ustawienie tego na Page spowoduje, że okno narzędzia będzie renderowane jako puste.
Krok 4. Dodaj polecenie, aby wyświetlić okno narzędzia
[VisualStudioContribution]
internal class ShowMyToolWindowCommand : Command
{
public ShowMyToolWindowCommand(VisualStudioExtensibility extensibility)
: base(extensibility)
{
}
public override CommandConfiguration CommandConfiguration => new("My Tool Window")
{
Placements = [CommandPlacement.KnownPlacements.ViewOtherWindowsMenu],
Icon = new(ImageMoniker.KnownValues.ToolWindow, IconSettings.IconAndText),
};
public override async Task ExecuteCommandAsync(IClientContext context, CancellationToken cancellationToken)
{
await Extensibility.Shell().ShowToolWindowAsync<MyToolWindow>(activate: true, cancellationToken);
}
}
Krok 5 (opcjonalnie): Dodać pasek narzędzi
Zdefiniuj pasek narzędzi i odwołaj się do niego w ToolWindowConfiguration:
[VisualStudioContribution]
public static ToolbarConfiguration MyToolbar => new("%MyToolbar.DisplayName%")
{
Children = [
ToolbarChild.Command<RefreshCommand>(),
ToolbarChild.Separator,
ToolbarChild.Command<ClearCommand>(),
],
};
public override ToolWindowConfiguration ToolWindowConfiguration => new()
{
Placement = ToolWindowPlacement.DocumentWell,
Toolbar = new(MyToolbar),
};
Porady
✅ DO
- Oznacz pliki XAML jako akcję kompilacji EmbeddedResource (a nie stronę).
- Użyj
[DataContract]i[DataMember]na właściwościach ViewModel dla zdalnego interfejsu użytkownika. - Użyj
NotifyPropertyChangedObjectjako podstawy dla modeli danych. - Zainicjuj dane w pliku
InitializeAsync(), utwórz interfejs użytkownika w plikuGetContentAsync(). - Użyj
ShowToolWindowAsync<T>(activate: true), aby wyświetlić dane wyjściowe poleceń.
❌ NIE RÓB
- Nie używaj WPF bezpośrednio — w przypadku rozszerzeń poza procesem wymagany jest zdalny interfejs użytkownika.
- Nie ustawiaj akcji kompilacji XAML na
Pagewartość (okno narzędzia nie będzie renderowane). - Nie twórz kosztownych zasobów w konstruktorze — użyj
InitializeAsync.
🔧 Rozwiązywanie problemów
| Objaw | Napraw. |
|---|---|
| Okno narzędzia jest puste | Sprawdź, czy akcja kompilacji XAML jest EmbeddedResource |
| Powiązanie danych nie jest aktualizowane | Upewnij się, że model ViewModel dziedziczy po NotifyPropertyChangedObject i właściwości mają [DataMember] |
| Okno się nie pojawia | Sprawdź, czy wywołania polecenia ShowToolWindowAsync są poprawne |
| Pasek narzędzi nie jest wyświetlany | Sprawdź, czy ToolWindowConfiguration.Toolbar ustawiono |
Następne kroki
- Omówienie zdalnego interfejsu użytkownika — zrozum model renderowania
- Dodaj polecenie — aby otworzyć okno narzędzia
- Motywy i kolory — nadaj styl interfejsowi użytkownika