11using System ;
22using Microsoft . VisualStudio . Shell ;
3+ using Microsoft . VisualStudio . Shell . Interop ;
34
45namespace Community . VisualStudio . Toolkit
56{
@@ -10,6 +11,8 @@ namespace Community.VisualStudio.Toolkit
1011 public abstract class ToolkitToolWindowPane : ToolWindowPane
1112 {
1213 private bool _isInitialized ;
14+ private WindowFrame ? _windowFrame ;
15+ private bool _isWindowFrameAvailable ;
1316
1417 /// <inheritdoc/>
1518 protected override void Initialize ( )
@@ -22,5 +25,72 @@ protected override void Initialize()
2225 internal bool IsInitialized => _isInitialized ;
2326
2427 internal event EventHandler ? Initialized ;
28+
29+ /// <inheritdoc/>
30+ public override void OnToolWindowCreated ( )
31+ {
32+ base . OnToolWindowCreated ( ) ;
33+ _isWindowFrameAvailable = true ;
34+ WindowFrameAvailable ? . Invoke ( this , EventArgs . Empty ) ;
35+ }
36+
37+ /// <summary>
38+ /// Indicates whether the <see cref="GetWindowFrame"/> method can be called.
39+ /// </summary>
40+ public bool IsWindowFrameAvailable => _isWindowFrameAvailable ;
41+
42+ /// <summary>
43+ /// Raised when Visual Studio creates the tool window's frame.
44+ /// The <see cref="WindowFrame"/> property can be accessed from this point onwards.
45+ /// </summary>
46+ public event EventHandler ? WindowFrameAvailable ;
47+
48+ /// <summary>
49+ /// Gets the tool window's window frame.
50+ /// <para>
51+ /// This method can only be called after Visual Studio has created the window frame.
52+ /// You can detect this in various ways:
53+ /// <list type="bullet">
54+ /// <item>
55+ /// Override the <see cref="OnToolWindowCreated"/> method.
56+ /// When this method is called, the window frame will be available.
57+ /// </item>
58+ /// <item>
59+ /// Listen for the <see cref="WindowFrameAvailable"/> event.
60+ /// When the event is raised, the window frame will be available.
61+ /// </item>
62+ /// <item>
63+ /// Check the <see cref="IsWindowFrameAvailable"/> property.
64+ /// </item>
65+ /// </list>
66+ /// </para>
67+ /// </summary>
68+ /// <exception cref="InvalidOperationException">The window frame is not available.</exception>
69+ protected WindowFrame GetWindowFrame ( )
70+ {
71+ if ( _windowFrame is null )
72+ {
73+ // The `Frame` property has to be set by Visual Studio, so it might
74+ // be null at this point. It's also typed as an `object` even though
75+ // internally it's stored as an `IVsWindowFrame`, so we can use
76+ // type matching to both cast and confirm that it's not null.
77+ if ( Frame is IVsWindowFrame vsWindowFrame )
78+ {
79+ // We could create the WindowFrame in `OnToolWindowCreated`,
80+ // but we delay-create it for two reasons:
81+ // 1. It may not ever be needed.
82+ // 2. If a derived class also overrides `OnToolWindowCreated`, then the window
83+ // frame would only be available after it called `base.OnToolWindowCreated()`.
84+ // Delay-creating it means that it will be available before that call is made.
85+ _windowFrame = new WindowFrame ( vsWindowFrame ) ;
86+ }
87+ else
88+ {
89+ throw new InvalidOperationException ( "The tool window's frame is not available yet." ) ;
90+ }
91+ }
92+
93+ return _windowFrame ;
94+ }
2595 }
2696}
0 commit comments