diff --git a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/ToolkitToolWindowPane.cs b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/ToolkitToolWindowPane.cs
index eea8866..84d0239 100644
--- a/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/ToolkitToolWindowPane.cs
+++ b/src/toolkit/Community.VisualStudio.Toolkit.Shared/Windows/ToolkitToolWindowPane.cs
@@ -1,5 +1,6 @@
using System;
using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
namespace Community.VisualStudio.Toolkit
{
@@ -10,6 +11,8 @@ namespace Community.VisualStudio.Toolkit
public abstract class ToolkitToolWindowPane : ToolWindowPane
{
private bool _isInitialized;
+ private WindowFrame? _windowFrame;
+ private bool _isWindowFrameAvailable;
///
protected override void Initialize()
@@ -22,5 +25,72 @@ protected override void Initialize()
internal bool IsInitialized => _isInitialized;
internal event EventHandler? Initialized;
+
+ ///
+ public override void OnToolWindowCreated()
+ {
+ base.OnToolWindowCreated();
+ _isWindowFrameAvailable = true;
+ WindowFrameAvailable?.Invoke(this, EventArgs.Empty);
+ }
+
+ ///
+ /// Indicates whether the method can be called.
+ ///
+ public bool IsWindowFrameAvailable => _isWindowFrameAvailable;
+
+ ///
+ /// Raised when Visual Studio creates the tool window's frame.
+ /// The property can be accessed from this point onwards.
+ ///
+ public event EventHandler? WindowFrameAvailable;
+
+ ///
+ /// Gets the tool window's window frame.
+ ///
+ /// This method can only be called after Visual Studio has created the window frame.
+ /// You can detect this in various ways:
+ ///
+ /// -
+ /// Override the method.
+ /// When this method is called, the window frame will be available.
+ ///
+ /// -
+ /// Listen for the event.
+ /// When the event is raised, the window frame will be available.
+ ///
+ /// -
+ /// Check the property.
+ ///
+ ///
+ ///
+ ///
+ /// The window frame is not available.
+ protected WindowFrame GetWindowFrame()
+ {
+ if (_windowFrame is null)
+ {
+ // The `Frame` property has to be set by Visual Studio, so it might
+ // be null at this point. It's also typed as an `object` even though
+ // internally it's stored as an `IVsWindowFrame`, so we can use
+ // type matching to both cast and confirm that it's not null.
+ if (Frame is IVsWindowFrame vsWindowFrame)
+ {
+ // We could create the WindowFrame in `OnToolWindowCreated`,
+ // but we delay-create it for two reasons:
+ // 1. It may not ever be needed.
+ // 2. If a derived class also overrides `OnToolWindowCreated`, then the window
+ // frame would only be available after it called `base.OnToolWindowCreated()`.
+ // Delay-creating it means that it will be available before that call is made.
+ _windowFrame = new WindowFrame(vsWindowFrame);
+ }
+ else
+ {
+ throw new InvalidOperationException("The tool window's frame is not available yet.");
+ }
+ }
+
+ return _windowFrame;
+ }
}
}