@@ -34,21 +34,23 @@ This example hides the default save as dialog and shows a customized dialog.
3434``` c++
3535bool ScenarioSaveAs::ToggleEventHandler ()
3636{
37- if (!m_webView2Staging20 )
37+ if (!m_webView2_20 )
3838 return false;
39+ // m_hasSaveAsRequestedEventHandler indicates whether the event handler
40+ // has been subscribed.
3941 if (m_hasSaveAsRequestedEventHandler)
4042 {
4143 // Unregister the handler for the `SaveAsRequested` event.
42- m_webView2Staging20 ->remove_SaveAsRequested(m_saveAsRequestedToken);
44+ m_webView2_20 ->remove_SaveAsRequested(m_saveAsRequestedToken);
4345 }
4446 else
4547 {
4648 // Register a handler for the `SaveAsRequested` event.
47- m_webView2Staging20 ->add_SaveAsRequested(
48- Callback<ICoreWebView2StagingSaveAsRequestedEventHandler >(
49+ m_webView2_20 ->add_SaveAsRequested(
50+ Callback<ICoreWebView2SaveAsRequestedEventHandler >(
4951 [this](
5052 ICoreWebView2* sender,
51- ICoreWebView2StagingSaveAsRequestedEventArgs * args) -> HRESULT
53+ ICoreWebView2SaveAsRequestedEventArgs * args) -> HRESULT
5254 {
5355 // Hide the system default save as dialog.
5456 CHECK_FAILURE (args->put_SuppressDefaultDialog(TRUE));
@@ -59,7 +61,6 @@ bool ScenarioSaveAs::ToggleEventHandler()
5961 wil::unique_cotaskmem_string mimeType;
6062 CHECK_FAILURE(args->get_ContentMimeType(&mimeType));
6163
62-
6364 // As an end developer, you can design your own dialog UI, or no UI at all.
6465 // You can ask the user information like file name, file extenstion, and etc.
6566 // Finally, concatenate and pass them into the event args
@@ -112,10 +113,10 @@ Call RequestSaveAs method to trigger the programmatic save as.
112113
113114bool ScenarioSaveAs::ProgrammaticSaveAs ()
114115{
115- if (!m_webView2Staging20 )
116+ if (!m_webView2_20 )
116117 return false;
117- m_webView2Staging20 ->RequestSaveAs(
118- Callback<ICoreWebView2StagingRequestSaveAsCompletedHandler >(
118+ m_webView2_20 ->RequestSaveAs(
119+ Callback<ICoreWebView2RequestSaveAsCompletedHandler >(
119120 [this](HRESULT errorCode, COREWEBVIEW2_SAVE_AS_REQUESTED_RESULTS result) -> HRESULT
120121 {
121122 // Show RequestSaveAs returned result, optional
@@ -129,10 +130,77 @@ bool ScenarioSaveAs::ProgrammaticSaveAs()
129130}
130131```
131132
133+ ## .Net/ WinRT
134+ ### Add or Remove the Event Handler
135+ This example hides the default save as dialog and shows a customized dialog.
136+ ``` c#
137+
138+ void TaggleEventHandlerExecuted (object target , ExecutedRoutedEventArgs e )
139+ {
140+ if (hasSaveAsRequestedEventHandler )
141+ webView .CoreWebView2 .SaveAsRequested -= WebView_SaveAsRequested ;
142+ else
143+ webView .CoreWebView2 .SaveAsRequested += WebView_SaveAsRequested ;
144+ hasSaveAsRequestedEventHandler = ! hasSaveAsRequestedEventHandler ;
145+ MessageBox .Show (hasSaveAsRequestedEventHandler ? " Event Handler Added" : " Event Handler Rremoved" , " Info" );
146+ }
147+
148+ void WebView_SaveAsRequested (object sender , CoreWebView2SaveAsRequestedEventArgs args )
149+ {
150+ // Hide the system default save as dialog.
151+ args .SuppressDefaultDialog = true ;
152+
153+ // Developer can obtain a deferral for the event so that the CoreWebView2
154+ // doesn't examine the properties we set on the event args until
155+ // after the deferral completes asynchronously.
156+ CoreWebView2Deferral deferral = args .GetDeferral ();
157+
158+ // We avoid potential reentrancy from running a message loop in the event
159+ // handler. Show the customized dialog later when complete the deferral
160+ // asynchronously.
161+ System .Threading .SynchronizationContext .Current .Post ((_ ) =>
162+ {
163+ using (deferral )
164+ {
165+ // This is a customized dialog example, the constructor returns after the
166+ // dialog interaction is completed by the end user.
167+ var dialog = new SaveAsDialog (_Kinds );
168+ if (dialog .ShowDialog () == true )
169+ {
170+ // Preview the content mime type, optional.
171+ args .ContentMimeType ;
172+
173+ // Setting parameters of event args from this dialog is optional.
174+ // The event args has default values.
175+ args .ResultFilePath = dialog .Directory .Text + " /" + dialog .Filename .Text ;
176+ args .Kind = (CoreWebView2SaveAsRequestedKind )dialog .Kind .SelectedItem ;
177+ args .AllowReplace = (bool )dialog .AllowReplaceOldFile .IsChecked ;
178+
179+ }
180+ else
181+ {
182+ // Save As cancelled from this customized dialog
183+ args .Cancel = true ;
184+ }
185+ }
186+ }, null );
187+ }
188+ ```
189+ ### Programmatic Save As
190+ Call RequestSaveAsAsync method to trigger the programmatic save as.
191+ ``` c#
192+ async void ProgrammaticSaveAsExecuted (object target , ExecutedRoutedEventArgs e )
193+ {
194+ CoreWebView2SaveAsRequestedResults result = await webView .CoreWebView2 .RequestSaveAsAsync ();
195+ // Show RequestSaveAsAsync returned result, optional
196+ MessageBox .Show (result .ToString (), " Info" );
197+ }
198+ ```
199+
132200# API Details
133201## Win32 C++
134202``` c++
135- // / Specifies save as requested kind selection options for `ICoreWebView2Staging20 `,
203+ // / Specifies save as requested kind selection options for `ICoreWebView2_20 `,
136204// / used in `SaveAsRequestedEventArgs`
137205// /
138206// / When the source is a html page, supports to select `HTML_ONLY`,
@@ -183,12 +251,12 @@ bool ScenarioSaveAs::ProgrammaticSaveAs()
183251 /// Did not perform Save As because the client side decided to cancel.
184252 COREWEBVIEW2_SAVE_AS_REQUESTED_CANCELLED,
185253 /// Save as requested completeed, the downloading would start
186- COREWEBVIEW2_SAVE_AS_REQUESTED_STARTED
254+ COREWEBVIEW2_SAVE_AS_REQUESTED_COMPLETED,
187255} COREWEBVIEW2_SAVE_AS_REQUESTED_RESULTS;
188256
189257
190258[uuid(15e1c6a3-c72a-4df3-91d7-d097fbec3bfd), object, pointer_default(unique)]
191- interface ICoreWebView2Staging20 : IUnknown {
259+ interface ICoreWebView2_20 : IUnknown {
192260 /// Programmatically trigger a save as action for current content. ` SaveAsRequested `
193261 /// event will be raised.
194262 ///
@@ -200,14 +268,14 @@ interface ICoreWebView2Staging20 : IUnknown {
200268 /// Please see COREWEBVIEW2_SAVE_AS_REQUESTED_RESULTS
201269 ///
202270 /// \snippet ScenarioSaveAs.cpp ProgrammaticSaveAs
203- HRESULT SaveContentAs([ in] ICoreWebView2StagingRequestSaveAsCompletedHandler * handler);
271+ HRESULT SaveContentAs([ in] ICoreWebView2RequestSaveAsCompletedHandler * handler);
204272
205273 /// Add an event handler for the ` SaveAsRequested ` event. This event is raised
206274 /// when save as is triggered, programmatically or manually.
207275 ///
208276 /// \snippet ScenarioSaveAs.cpp ToggleEventHandler
209277 HRESULT add_SaveAsRequested(
210- [ in] ICoreWebView2StagingSaveAsRequestedEventHandler * eventHanlder,
278+ [ in] ICoreWebView2SaveAsRequestedEventHandler * eventHanlder,
211279 [ out] EventRegistrationToken* token);
212280
213281 /// Remove an event handler previously added with ` add_SaveAsRequested ` .
@@ -219,15 +287,15 @@ interface ICoreWebView2Staging20 : IUnknown {
219287
220288// / The event handler for the `SaveAsRequested` event.
221289[uuid(55b86cd2-adfd-47f1-9cef-cdfb8c414ed3), object, pointer_default(unique)]
222- interface ICoreWebView2StagingSaveAsRequestedEventHandler : IUnknown {
290+ interface ICoreWebView2SaveAsRequestedEventHandler : IUnknown {
223291 HRESULT Invoke(
224292 [ in] ICoreWebView2* sender,
225- [ in] ICoreWebView2StagingSaveAsRequestedEventArgs * args);
293+ [ in] ICoreWebView2SaveAsRequestedEventArgs * args);
226294}
227295
228296// / The event args for `SaveAsRequested` event
229297[uuid(80101027 -b8c3-49a1-a052-9ea4bd63ba47), object, pointer_default(unique)]
230- interface ICoreWebView2StagingSaveAsRequestedEventArgs : IUnknown {
298+ interface ICoreWebView2SaveAsRequestedEventArgs : IUnknown {
231299 /// Get the Mime type of content to be saved
232300 [ propget] HRESULT ContentMimeType([ out, retval] LPWSTR* value);
233301
@@ -306,7 +374,57 @@ interface ICoreWebView2StagingSaveAsRequestedEventArgs : IUnknown {
306374
307375// / Receive the result for `RequestSaveAs` method
308376[uuid(1a02e9d9-14d3-41c6-9581 -8d6e1e6f50fe), object, pointer_default(unique)]
309- interface ICoreWebView2StagingRequestSaveAsCompletedHandler : IUnknown {
377+ interface ICoreWebView2RequestSaveAsCompletedHandler : IUnknown {
310378 HRESULT Invoke([ in] HRESULT errorCode, [ in] COREWEBVIEW2_REQUEST_SAVE_RESULTS result);
311379}
312380```
381+
382+ ## .Net/ WinRT
383+ ``` c# (but really MIDL3)
384+ namespace Microsoft .Web .WebView2 .Core
385+ {
386+
387+ runtimeclass CoreWebView2SaveAsRequestedEventArgs;
388+ runtimeclass CoreWebView2;
389+
390+ enum CoreWebView2SaveAsRequestedResults
391+ {
392+ InvalidPath = 0 ,
393+ FileAlreadyExists = 1 ,
394+ KindNotSupported = 2 ,
395+ Cancelled = 3 ,
396+ Completed = 4 ,
397+ };
398+
399+ enum CoreWebView2SaveAsRequestedKind
400+ {
401+ Default = 0 ,
402+ HtmlOnly = 1 ,
403+ SingleFile = 2 ,
404+ Complete = 3 ,
405+ };
406+
407+ runtimeclass CoreWebView2SaveAsRequestedEventArgs
408+ {
409+ String ContentMimeType { get; };
410+ Boolean Cancel { get ; set ; };
411+ Boolean SuppressDefaultDialog { get ; set ; };
412+ String ResultFilePath { get ; set ; };
413+ Boolean AllowReplace { get ; set ; };
414+ CoreWebView2SaveAsRequestedKind Kind { get ; set ; };
415+ Windows .Foundation .Deferral GetDeferral ();
416+ };
417+
418+ runtimeclass CoreWebView2
419+ {
420+ [interface_name (" Microsoft.Web.WebView2.Core.ICoreWebView2_20" )]
421+ {
422+ // ...
423+ event Windows .Foundation .TypedEventHandler
424+ < CoreWebView2 , CoreWebView2SaveAsRequestedEventArgs > SaveAsRequested ;
425+ Windows .Foundation .IAsyncOperation < CoreWebView2SaveAsRequestedResults >
426+ RequestSaveAsAsync ();
427+ }
428+ };
429+ }
430+ ```
0 commit comments