Skip to content

Commit 85f3f7c

Browse files
committed
Allowed a tool window or its content to get access to the ToolWindowPane.
1 parent 97e1577 commit 85f3f7c

File tree

8 files changed

+104
-3
lines changed

8 files changed

+104
-3
lines changed

demo/VSSDK.TestExtension/ToolWindows/RunnerWindow.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public override async Task<FrameworkElement> CreateAsync(int toolWindowId, Cance
2424
}
2525

2626
[Guid("d3b3ebd9-87d1-41cd-bf84-268d88953417")]
27-
internal class Pane : ToolWindowPane
27+
internal class Pane : ToolkitToolWindowPane
2828
{
2929
public Pane()
3030
{

demo/VSSDK.TestExtension/ToolWindows/RunnerWindowControl.xaml.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
using Community.VisualStudio.Toolkit;
66
using Microsoft.VisualStudio;
77
using Microsoft.VisualStudio.Shell;
8+
using Microsoft.VisualStudio.Shell.Interop;
89
using Task = System.Threading.Tasks.Task;
910

1011
namespace TestExtension
1112
{
12-
public partial class RunnerWindowControl : UserControl
13+
public partial class RunnerWindowControl : UserControl, IToolWindowPaneAware
1314
{
1415
public RunnerWindowControl(Version vsVersion, RunnerWindowMessenger messenger)
1516
{
@@ -55,5 +56,10 @@ private async Task HideAsync()
5556
{
5657
await RunnerWindow.HideAsync();
5758
}
59+
60+
public void SetPane(ToolWindowPane pane)
61+
{
62+
MessageList.Items.Add("Pane has been set.");
63+
}
5864
}
5965
}

src/toolkit/Community.VisualStudio.Toolkit.Shared/ToolkitPackage.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,20 @@ protected override WindowPane InstantiateToolWindow(Type toolWindowType, object
8989
toolPane.Caption = provider.GetTitle(data.Id);
9090
}
9191

92+
// Now we can try to give the pane object to the tool window implementation and the content
93+
// if they want to know about the pane. At this point the pane has probably not been initialized,
94+
// and if it hasn't, then it won't be initialized until some time after we return from this method.
95+
// We could given the pane to the tool window implementation, but you can't use the pane until it has
96+
// been initialized, and there's no way to know when it has been initialized unless you implement your
97+
// own logic in your ToolWindowPane implementation. To provide a better user experience, if your tool
98+
// window needs access to the window pane, then we will require that the pane inherit from our custom
99+
// `ToolkitWindowPane` class. This implementation allows us to detect if and when the pane is initialized.
100+
// Once the pane has been initialized, we can given the pane to the tool window and its content.
101+
if (pane is ToolkitToolWindowPane toolkitPane)
102+
{
103+
ProvidePaneToToolWindow(toolkitPane, data.Id, provider);
104+
}
105+
92106
return pane;
93107
}
94108
else
@@ -97,6 +111,24 @@ protected override WindowPane InstantiateToolWindow(Type toolWindowType, object
97111
}
98112
}
99113

114+
private void ProvidePaneToToolWindow(ToolkitToolWindowPane pane, int toolWindowId, IToolWindowProvider provider)
115+
{
116+
if (pane.IsInitialized)
117+
{
118+
OnInitialized(pane, EventArgs.Empty);
119+
}
120+
else
121+
{
122+
pane.Initialized += OnInitialized;
123+
}
124+
125+
void OnInitialized(object s, EventArgs e)
126+
{
127+
provider.SetPane(pane, toolWindowId);
128+
(pane.Content as IToolWindowPaneAware)?.SetPane(pane);
129+
}
130+
}
131+
100132
private class InstantiateToolWindowData
101133
{
102134
public InstantiateToolWindowData(int id, FrameworkElement content)

src/toolkit/Community.VisualStudio.Toolkit.Shared/VSSDK.Helpers.Shared.projitems

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
</PropertyGroup>
1111
<ItemGroup>
1212
<Compile Include="$(MSBuildThisFileDirectory)Debugger\Debugger.cs" />
13+
<Compile Include="$(MSBuildThisFileDirectory)Windows\IToolWindowPaneAware.cs" />
14+
<Compile Include="$(MSBuildThisFileDirectory)Windows\ToolkitToolWindowPane.cs" />
1315
<Compile Include="$(MSBuildThisFileDirectory)\Attributes\ProvideBraceCompletionAttribute.cs" />
1416
<Compile Include="$(MSBuildThisFileDirectory)\Attributes\ProvideFileIconAttribute.cs" />
1517
<Compile Include="$(MSBuildThisFileDirectory)\Attributes\ProvideGalleryFeedAttribute.cs" />

src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/BaseToolWindow.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace Community.VisualStudio.Toolkit
2929
/// }
3030
///
3131
/// [Guid("d0050678-2e4f-4a93-adcb-af1370da941d")]
32-
/// internal class Pane : ToolWindowPane
32+
/// internal class Pane : ToolkitToolWindowPane
3333
/// {
3434
/// public Pane()
3535
/// {
@@ -164,5 +164,16 @@ public static async Task<bool> HideAsync(int id = 0)
164164
/// <param name="cancellationToken">The cancellation token to use when performing asynchronous operations.</param>
165165
/// <returns>The UI element to show in the tool window.</returns>
166166
public abstract Task<FrameworkElement> CreateAsync(int toolWindowId, CancellationToken cancellationToken);
167+
168+
/// <summary>
169+
/// Called when the <see cref="ToolWindowPane"/> has been initialized and "sited".
170+
/// The pane's service provider can be used from this point onwards.
171+
/// </summary>
172+
/// <param name="pane">The tool window pane that was created.</param>
173+
/// <param name="toolWindowId">The ID of the tool window that the pane belongs to.</param>
174+
public virtual void SetPane(ToolWindowPane pane, int toolWindowId)
175+
{
176+
// Consumers can override this if they need access to the pane.
177+
}
167178
}
168179
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Microsoft.VisualStudio.Shell;
2+
3+
namespace Community.VisualStudio.Toolkit
4+
{
5+
/// <summary>
6+
/// Allows the content of a <see cref="ToolWindowPane"/> to be aware of its owning <see cref="ToolWindowPane"/> object.
7+
/// <para>
8+
/// Implement this interface on your tool window's content (the object you return from
9+
/// <see cref="BaseToolWindow{T}.CreateAsync(int, System.Threading.CancellationToken)"/>)
10+
/// if you need the content object to have access to its <see cref="ToolWindowPane"/>.
11+
/// </para>
12+
/// </summary>
13+
public interface IToolWindowPaneAware
14+
{
15+
/// <summary>
16+
/// Called when the <see cref="ToolWindowPane"/> has been initialized and "sited".
17+
/// The pane's service provider can be used from this point onwards.
18+
/// </summary>
19+
/// <param name="pane">The tool window pane that was created.</param>
20+
void SetPane(ToolWindowPane pane);
21+
}
22+
}

src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/IToolWindowProvider.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Threading;
33
using System.Threading.Tasks;
44
using System.Windows;
5+
using Microsoft.VisualStudio.Shell;
56

67
namespace Community.VisualStudio.Toolkit
78
{
@@ -12,5 +13,7 @@ internal interface IToolWindowProvider
1213
public Type PaneType { get; }
1314

1415
public Task<FrameworkElement> CreateAsync(int toolWindowId, CancellationToken cancellationToken);
16+
17+
public void SetPane(ToolWindowPane pane, int toolWindowId);
1518
}
1619
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using Microsoft.VisualStudio.Shell;
3+
4+
namespace Community.VisualStudio.Toolkit
5+
{
6+
/// <summary>
7+
/// An implementation of <see cref="ToolWindowPane"/> that allows the
8+
/// </summary>
9+
public abstract class ToolkitToolWindowPane : ToolWindowPane
10+
{
11+
private bool _isInitialized;
12+
13+
/// <inheritdoc/>
14+
protected override void Initialize()
15+
{
16+
base.Initialize();
17+
_isInitialized = true;
18+
Initialized?.Invoke(this, EventArgs.Empty);
19+
}
20+
21+
internal bool IsInitialized => _isInitialized;
22+
23+
internal event EventHandler? Initialized;
24+
}
25+
}

0 commit comments

Comments
 (0)