diff --git a/demo/VSSDK.TestExtension/ToolWindows/RunnerWindow.cs b/demo/VSSDK.TestExtension/ToolWindows/RunnerWindow.cs index 2871952..8bcd501 100644 --- a/demo/VSSDK.TestExtension/ToolWindows/RunnerWindow.cs +++ b/demo/VSSDK.TestExtension/ToolWindows/RunnerWindow.cs @@ -24,7 +24,7 @@ public override async Task CreateAsync(int toolWindowId, Cance } [Guid("d3b3ebd9-87d1-41cd-bf84-268d88953417")] - internal class Pane : ToolWindowPane + internal class Pane : ToolkitToolWindowPane { public Pane() { diff --git a/demo/VSSDK.TestExtension/ToolWindows/RunnerWindowControl.xaml.cs b/demo/VSSDK.TestExtension/ToolWindows/RunnerWindowControl.xaml.cs index 931cb79..072406e 100644 --- a/demo/VSSDK.TestExtension/ToolWindows/RunnerWindowControl.xaml.cs +++ b/demo/VSSDK.TestExtension/ToolWindows/RunnerWindowControl.xaml.cs @@ -5,11 +5,12 @@ using Community.VisualStudio.Toolkit; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; using Task = System.Threading.Tasks.Task; namespace TestExtension { - public partial class RunnerWindowControl : UserControl + public partial class RunnerWindowControl : UserControl, IToolWindowPaneAware { public RunnerWindowControl(Version vsVersion, RunnerWindowMessenger messenger) { @@ -55,5 +56,10 @@ private async Task HideAsync() { await RunnerWindow.HideAsync(); } + + public void SetPane(ToolWindowPane pane) + { + MessageList.Items.Add("Pane has been set."); + } } } \ No newline at end of file diff --git a/src/toolkit/Community.VisualStudio.Toolkit.Shared/ToolkitPackage.cs b/src/toolkit/Community.VisualStudio.Toolkit.Shared/ToolkitPackage.cs index 8344b0e..c73af10 100644 --- a/src/toolkit/Community.VisualStudio.Toolkit.Shared/ToolkitPackage.cs +++ b/src/toolkit/Community.VisualStudio.Toolkit.Shared/ToolkitPackage.cs @@ -89,6 +89,20 @@ protected override WindowPane InstantiateToolWindow(Type toolWindowType, object toolPane.Caption = provider.GetTitle(data.Id); } + // Now we can try to give the pane object to the tool window implementation and the content + // if they want to know about the pane. At this point the pane has probably not been initialized, + // and if it hasn't, then it won't be initialized until some time after we return from this method. + // We could given the pane to the tool window implementation, but you can't use the pane until it has + // been initialized, and there's no way to know when it has been initialized unless you implement your + // own logic in your ToolWindowPane implementation. To provide a better user experience, if your tool + // window needs access to the window pane, then we will require that the pane inherit from our custom + // `ToolkitWindowPane` class. This implementation allows us to detect if and when the pane is initialized. + // Once the pane has been initialized, we can given the pane to the tool window and its content. + if (pane is ToolkitToolWindowPane toolkitPane) + { + ProvidePaneToToolWindow(toolkitPane, data.Id, provider); + } + return pane; } else @@ -97,6 +111,24 @@ protected override WindowPane InstantiateToolWindow(Type toolWindowType, object } } + private void ProvidePaneToToolWindow(ToolkitToolWindowPane pane, int toolWindowId, IToolWindowProvider provider) + { + if (pane.IsInitialized) + { + OnInitialized(pane, EventArgs.Empty); + } + else + { + pane.Initialized += OnInitialized; + } + + void OnInitialized(object s, EventArgs e) + { + provider.SetPane(pane, toolWindowId); + (pane.Content as IToolWindowPaneAware)?.SetPane(pane); + } + } + private class InstantiateToolWindowData { public InstantiateToolWindowData(int id, FrameworkElement content) diff --git a/src/toolkit/Community.VisualStudio.Toolkit.Shared/VSSDK.Helpers.Shared.projitems b/src/toolkit/Community.VisualStudio.Toolkit.Shared/VSSDK.Helpers.Shared.projitems index a1c8d26..968b78f 100644 --- a/src/toolkit/Community.VisualStudio.Toolkit.Shared/VSSDK.Helpers.Shared.projitems +++ b/src/toolkit/Community.VisualStudio.Toolkit.Shared/VSSDK.Helpers.Shared.projitems @@ -10,6 +10,8 @@ + + diff --git a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/BaseToolWindow.cs b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/BaseToolWindow.cs index 44768e5..f827fac 100644 --- a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/BaseToolWindow.cs +++ b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/BaseToolWindow.cs @@ -29,7 +29,7 @@ namespace Community.VisualStudio.Toolkit /// } /// /// [Guid("d0050678-2e4f-4a93-adcb-af1370da941d")] - /// internal class Pane : ToolWindowPane + /// internal class Pane : ToolkitToolWindowPane /// { /// public Pane() /// { @@ -164,5 +164,16 @@ public static async Task HideAsync(int id = 0) /// The cancellation token to use when performing asynchronous operations. /// The UI element to show in the tool window. public abstract Task CreateAsync(int toolWindowId, CancellationToken cancellationToken); + + /// + /// Called when the has been initialized and "sited". + /// The pane's service provider can be used from this point onwards. + /// + /// The tool window pane that was created. + /// The ID of the tool window that the pane belongs to. + public virtual void SetPane(ToolWindowPane pane, int toolWindowId) + { + // Consumers can override this if they need access to the pane. + } } } diff --git a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/IToolWindowPaneAware.cs b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/IToolWindowPaneAware.cs new file mode 100644 index 0000000..c1fc95c --- /dev/null +++ b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/IToolWindowPaneAware.cs @@ -0,0 +1,22 @@ +using Microsoft.VisualStudio.Shell; + +namespace Community.VisualStudio.Toolkit +{ + /// + /// Allows the content of a to be aware of its owning object. + /// + /// Implement this interface on your tool window's content (the object you return from + /// ) + /// if you need the content object to have access to its . + /// + /// + public interface IToolWindowPaneAware + { + /// + /// Called when the has been initialized and "sited". + /// The pane's service provider can be used from this point onwards. + /// + /// The tool window pane that was created. + void SetPane(ToolWindowPane pane); + } +} diff --git a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/IToolWindowProvider.cs b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/IToolWindowProvider.cs index 54f1eef..3289d66 100644 --- a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/IToolWindowProvider.cs +++ b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/IToolWindowProvider.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; +using Microsoft.VisualStudio.Shell; namespace Community.VisualStudio.Toolkit { @@ -12,5 +13,7 @@ internal interface IToolWindowProvider public Type PaneType { get; } public Task CreateAsync(int toolWindowId, CancellationToken cancellationToken); + + public void SetPane(ToolWindowPane pane, int toolWindowId); } } diff --git a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/ToolkitToolWindowPane.cs b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/ToolkitToolWindowPane.cs new file mode 100644 index 0000000..6856922 --- /dev/null +++ b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/ToolkitToolWindowPane.cs @@ -0,0 +1,25 @@ +using System; +using Microsoft.VisualStudio.Shell; + +namespace Community.VisualStudio.Toolkit +{ + /// + /// An implementation of that allows the + /// + public abstract class ToolkitToolWindowPane : ToolWindowPane + { + private bool _isInitialized; + + /// + protected override void Initialize() + { + base.Initialize(); + _isInitialized = true; + Initialized?.Invoke(this, EventArgs.Empty); + } + + internal bool IsInitialized => _isInitialized; + + internal event EventHandler? Initialized; + } +}