Skip to content

Commit 132f3f6

Browse files
author
Wangsong Jin
committed
Added Spec for CoreWebView2Frame::FrameCreated API
1 parent 47b5622 commit 132f3f6

File tree

1 file changed

+269
-0
lines changed

1 file changed

+269
-0
lines changed

specs/NestedFrame.md

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
CoreWebView2Frame.FrameCreated API
2+
===
3+
4+
# Background
5+
At present, WebView2 enables developers to track only
6+
first-level iframes, which are the direct child frames
7+
of the main frame. However, we're noticing WebView2
8+
customers want to manage nested iframes, such as
9+
recording the navigation history for a nested iframe.
10+
To address this, we will introduce the
11+
`CoreWebView2Frame.FrameCreated` API. This new API will allow
12+
developers to subscribe to the event when a nested WebView frame
13+
is created, giving them access to all properties, methods, and
14+
events of [CoreWebView2Frame](https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2frame)
15+
for the nested WebView frame.
16+
17+
To prevent unnecessary performance overhead, WebView2
18+
does not track any nested WebView frames by default.
19+
It only tracks a webview2 frame if its parent webview2
20+
frame has subscribed to the `CoreWebView2Frame.FrameCreated`
21+
API. Therefore, WebView2 developers have the flexibility
22+
to choose whether they want to track specific branches of
23+
the frame tree or all webview2 frames.
24+
25+
# Examples
26+
### C++ Sample
27+
```cpp
28+
EventRegistrationToken m_frameCreatedToken = {};
29+
30+
void PostFrameCreatedEventMessage(wil::com_ptr<ICoreWebView2Frame> webviewFrame);
31+
32+
void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEventView)
33+
{
34+
auto webviewEventView4 = webviewEventView.try_query<ICoreWebView2_4>();
35+
webviewEventView4->add_FrameCreated(
36+
Callback<ICoreWebView2FrameCreatedEventHandler>(
37+
[this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args)
38+
-> HRESULT {
39+
wil::com_ptr<ICoreWebView2Frame> webviewFrame;
40+
CHECK_FAILURE(args->get_Frame(&webviewFrame));
41+
// Track first-level webview frame events.
42+
InitializeFrameEventView(webviewFrame);
43+
PostFrameCreatedEventMessage(webviewFrame);
44+
return S_OK;
45+
})
46+
.Get(),
47+
&m_frameCreatedToken);
48+
}
49+
50+
// Track the creation, destruction, and navigation events of webview frames.
51+
void ScenarioWebViewEventMonitor::InitializeFrameEventView(
52+
wil::com_ptr<ICoreWebView2Frame> webviewFrame) {
53+
auto frame7 = webviewFrame.try_query<ICoreWebView2Frame7>();
54+
if (frame7)
55+
{
56+
//! [AddFrameCreated]
57+
frame7->add_FrameCreated(
58+
Callback<ICoreWebView2FrameNestedFrameCreatedEventHandler>(
59+
[this](
60+
ICoreWebView2Frame* sender,
61+
ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT
62+
{
63+
wil::com_ptr<ICoreWebView2Frame> webviewFrame;
64+
CHECK_FAILURE(args->get_Frame(&webviewFrame));
65+
// Make a recursive call to track all nested
66+
// webview frame events.
67+
InitializeFrameEventView(webviewFrame);
68+
PostFrameCreatedEventMessage(webviewFrame);
69+
return S_OK;
70+
})
71+
.Get(),
72+
&m_frameCreatedToken);
73+
//! [AddFrameCreated]
74+
}
75+
76+
// Subscribe to webview frame destroyed event.
77+
webviewFrame->add_Destroyed(
78+
Callback<ICoreWebView2FrameDestroyedEventHandler>(
79+
[this](ICoreWebView2Frame* sender, IUnknown* args) -> HRESULT
80+
{
81+
wil::unique_cotaskmem_string name;
82+
CHECK_FAILURE(sender->get_Name(&name));
83+
std::wstring message = L"{ \"kind\": \"event\", \"name\": "
84+
L"\"CoreWebView2Frame::Destroyed\", \"args\": {";
85+
message += L"\"frame name\": " + EncodeQuote(name.get());
86+
message +=
87+
L"}" + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + L"}";
88+
PostEventMessage(message);
89+
return S_OK;
90+
})
91+
.Get(),
92+
NULL);
93+
94+
// Subscribe to webview frame navigation events.
95+
wil::com_ptr<ICoreWebView2Frame2> frame2 = webviewFrame.try_query<ICoreWebView2Frame2>();
96+
if (frame2)
97+
{
98+
frame2->add_NavigationStarting(
99+
Callback<ICoreWebView2FrameNavigationStartingEventHandler>(
100+
[this](
101+
ICoreWebView2Frame* sender,
102+
ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT {
103+
std::wstring message = NavigationStartingArgsToJsonString(
104+
m_webviewEventSource.get(), args,
105+
L"CoreWebView2Frame::NavigationStarting");
106+
PostEventMessage(message);
107+
return S_OK;
108+
})
109+
.Get(),
110+
NULL);
111+
112+
frame2->add_ContentLoading(
113+
Callback<ICoreWebView2FrameContentLoadingEventHandler>(
114+
[this](ICoreWebView2Frame* sender, ICoreWebView2ContentLoadingEventArgs* args)
115+
-> HRESULT {
116+
std::wstring message = ContentLoadingArgsToJsonString(
117+
m_webviewEventSource.get(), args, L"CoreWebView2Frame::ContentLoading");
118+
PostEventMessage(message);
119+
return S_OK;
120+
})
121+
.Get(),
122+
NULL);
123+
124+
frame2->add_DOMContentLoaded(
125+
Callback<ICoreWebView2FrameDOMContentLoadedEventHandler>(
126+
[this](ICoreWebView2Frame* sender, ICoreWebView2DOMContentLoadedEventArgs* args)
127+
-> HRESULT {
128+
std::wstring message = DOMContentLoadedArgsToJsonString(
129+
m_webviewEventSource.get(), args,
130+
L"CoreWebView2Frame::DOMContentLoaded");
131+
PostEventMessage(message);
132+
return S_OK;
133+
})
134+
.Get(),
135+
NULL);
136+
137+
frame2->add_NavigationCompleted(
138+
Callback<ICoreWebView2FrameNavigationCompletedEventHandler>(
139+
[this](
140+
ICoreWebView2Frame* sender,
141+
ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT {
142+
std::wstring message = NavigationCompletedArgsToJsonString(
143+
m_webviewEventSource.get(), args,
144+
L"CoreWebView2Frame::NavigationCompleted");
145+
PostEventMessage(message);
146+
return S_OK;
147+
})
148+
.Get(),
149+
NULL);
150+
}
151+
}
152+
153+
void ScenarioWebViewEventMonitor::PostFrameCreatedEventMessage(wil::com_ptr<ICoreWebView2Frame> webviewFrame) {
154+
wil::unique_cotaskmem_string name;
155+
CHECK_FAILURE(webviewFrame->get_Name(&name));
156+
auto frame5 = webviewFrame.try_query<ICoreWebView2Frame5>();
157+
if (frame5)
158+
{
159+
UINT32 frameId = 0;
160+
CHECK_FAILURE(frame5->get_FrameId(&frameId));
161+
}
162+
163+
std::wstring message =
164+
L"{ \"kind\": \"event\", \"name\": \"FrameCreated\", \"args\": {";
165+
166+
message += L"\"frame\": " + EncodeQuote(name.get());
167+
message += L",\"webview frame Id\": " + std::to_wstring((int)frameId) + L"}";
168+
message +=
169+
WebViewPropertiesToJsonString(m_webview.get());
170+
message += L"}";
171+
PostEventMessage(message);
172+
}
173+
```
174+
### C# Sample
175+
```c#
176+
// Track first-level webview frame created event.
177+
void ChildFrameEventsExecuted(object target, ExecutedRoutedEventArgs e)
178+
{
179+
webView.CoreWebView2.FrameCreated += HandleChildFrameCreated;
180+
}
181+
182+
// Track the creation, destruction, and navigation events of webview frames.
183+
void HandleChildFrameCreated(object sender, CoreWebView2FrameCreatedEventArgs args)
184+
{
185+
CoreWebView2Frame childFrame = args.Frame;
186+
string name = String.IsNullOrEmpty(childFrame.Name) ? "none" : childFrame.Name;
187+
MessageBox.Show(this, "Id: " + childFrame.FrameId + " name: " + name, "Child frame created", MessageBoxButton.OK);
188+
// Make a recursive call to track all nested webview2 frames events.
189+
childFrame.FrameCreated += HandleChildFrameCreated;
190+
childFrame.NavigationStarting += HandleChildFrameNavigationStarting;
191+
childFrame.ContentLoading += HandleChildFrameContentLoading;
192+
childFrame.DOMContentLoaded += HandleChildFrameDOMContentLoaded;
193+
childFrame.NavigationCompleted += HandleChildFrameNavigationCompleted;
194+
childFrame.Destroyed += HandleChildFrameDestroyed;
195+
}
196+
197+
void HandleChildFrameDestroyed(object sender, object args) {
198+
CoreWebView2Frame frame = (CoreWebView2Frame)sender;
199+
MessageBox.Show(this, "Id: " + frame.FrameId + " FrameDestroyed", "Child frame Destroyed", MessageBoxButton.OK);
200+
}
201+
202+
void HandleChildFrameNavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs args)
203+
{
204+
CoreWebView2Frame frame = (CoreWebView2Frame)sender;
205+
MessageBox.Show(this, "Id: " + frame.FrameId + " NavigationStarting", "Child frame Navigation", MessageBoxButton.OK);
206+
}
207+
208+
void HandleChildFrameContentLoading(object sender, CoreWebView2ContentLoadingEventArgs args)
209+
{
210+
CoreWebView2Frame frame = (CoreWebView2Frame)sender;
211+
MessageBox.Show(this, "Id: " + frame.FrameId + " ContentLoading", "Child frame Content Loading", MessageBoxButton.OK);
212+
}
213+
214+
void HandleChildFrameDOMContentLoaded(object sender, CoreWebView2DOMContentLoadedEventArgs args)
215+
{
216+
CoreWebView2Frame frame = (CoreWebView2Frame)sender;
217+
MessageBox.Show(this, "Id: " + frame.FrameId + " DOMContentLoaded", "Child frame DOM Content Loaded", MessageBoxButton.OK);
218+
}
219+
220+
void HandleChildFrameNavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs args)
221+
{
222+
CoreWebView2Frame frame = (CoreWebView2Frame)sender;
223+
MessageBox.Show(this, "Id: " + frame.FrameId + " NavigationCompleted", "Child frame Navigation Completed", MessageBoxButton.OK);
224+
}
225+
```
226+
227+
# API Details
228+
## C++
229+
```
230+
/// Receives `FrameCreated` events.
231+
interface ICoreWebView2FrameNestedFrameCreatedEventHandler : IUnknown {
232+
/// Provides the event args for the corresponding event.
233+
HRESULT Invoke(
234+
[in] ICoreWebView2Frame* sender,
235+
[in] ICoreWebView2FrameCreatedEventArgs* args);
236+
}
237+
238+
/// This is the ICoreWebView2Frame interface.
239+
interface ICoreWebView2Frame7 : IUnknown {
240+
/// Adds an event handler for the `FrameCreated` event.
241+
/// Raised when a new direct descendant iframe is created.
242+
/// Handle this event to get access to ICoreWebView2Frame objects.
243+
/// Use `ICoreWebView2Frame.add_Destroyed` to listen for when this
244+
/// iframe goes away.
245+
///
246+
/// \snippet ScenarioWebViewEventMonitor.cpp FrameCreated1
247+
HRESULT add_FrameCreated(
248+
[in] ICoreWebView2FrameNestedFrameCreatedEventHandler* eventHandler,
249+
[out] EventRegistrationToken* token);
250+
251+
/// Removes an event handler previously added with `add_FrameCreated`.
252+
HRESULT remove_FrameCreated(
253+
[in] EventRegistrationToken token);
254+
}
255+
```
256+
257+
C#
258+
```c#
259+
namespace Microsoft.Web.WebView2.Core
260+
{
261+
runtimeclass CoreWebView2Frame
262+
{
263+
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Frame7")]
264+
{
265+
event Windows.Foundation.TypedEventHandler<CoreWebView2Frame, CoreWebView2FrameCreatedEventArgs> FrameCreated;
266+
}
267+
}
268+
}
269+
```

0 commit comments

Comments
 (0)