IWebViewShowCreatedWebView EventAwesomium.NET 1.7.6Awesomium.NET
Occurs when an IWebView creates a new child web-view instance (usually the result of window.open or an external link).

Namespace: Awesomium.Core
Assembly: Awesomium.Core (in Awesomium.Core.dll) Version: 1.7.6.0
Syntax

event ShowCreatedWebViewEventHandler ShowCreatedWebView

Value

Type: Awesomium.CoreShowCreatedWebViewEventHandler
Remarks

ShowCreatedWebView occurs when an IWebView instance creates a new child view (usually the result of window.open, clicking on a link with target="_blank" or submitting a form with target="_blank").

It is your responsibility to wrap and display this new view in your application.

Note Note
The ShowCreatedWebView event must always be handled in your application to wrap views created by Awesomium in response to users clicking a link or JavaScript window.open calls.

If you don't handle this event, the unused web-view instance will be immediately destroyed.

There are a number of facts you need to take into consideration, before taking the appropriate actions in response to a ShowCreatedWebView event. The following list presents these facts and some general suggestions:
  • The created child view, has the same type (see ViewType) and is assigned to the same session (see WebSession) as its parent (opener) view. Therefore, you should not attempt to set these properties if you are wrapping the new child view with a technology specific WebControl.
  • In order to maintain the relationship with their parent view, child views execute and render under the same process (awesomium_process) as their parent view. If for any reason the child process crashes, all views related to it will be affected.
  • If ShowCreatedWebView is fired as a result of a Javascript window.open, IsWindowOpen will be true. In this scenario, you should always wrap the created child view instance (NewViewInstance), to maintain the parent-child window relationship (the child page can access the parent through the window.opener property; the parent can manipulate the child through the window object returned from the window.open call, which is why window.open was most probably used in the first place).
  • If ShowCreatedWebView is fired as a result of an HTML form with target="_blank" and method="post", IsPost will be true. In this scenario, you should always wrap the created child view instance (NewViewInstance), to allow POST data be properly passed.
  • When IsWindowOpen or IsPost are false, it most possibly indicates that the event is the result of a user clicking on a link with target="_blank". Since maintaining a parent-child relationship is not important in this scenario, you should cancel the event by setting Cancel to true (this tells the core to destroy the unused web-view instance), then create a new WebView (using CreateWebView(Int32, Int32, WebSession, WebViewType)) or WebControl and navigate to the provided TargetURL, if any. This allows you to take advantage of the isolated process architecture of Awesomium and let each view be rendered in a separate process.
    Caution note Caution
    Failing to cancel the event when you are not wrapping the new child view instance, will keep the native instance alive until the WebCore is shut down. This can result in numerous unused views being spawned, but never actually used.
  • When IsWindowOpen or IsPost is true, navigation to the TargetURL, if any, is already queued on the created child view. Therefore you should not attempt to set the Source when you are wrapping the child view, as this would again break the parent-child relationship (window.opener on the child page and the window object returned from the window.open call on the parent page, will be rendered invalid) or prevent passing POST data to the server respectively.
    Note Note
    Also note that since navigation to the TargetURL, if any, has already started by the moment the child view is wrapped, LoadingFrame will not be fired for the main frame of the new IWebView instance.
  • Navigation to the TargetURL, if any, is blocked on the created child view, when IsWindowOpen and IsPost are false. As applications will generally choose to cancel the event and create a new IWebView instance to navigate to the target URL (or even choose to navigate to the target URL on the same IWebView instance that fired the event), Awesomium.NET does this to prevent false hits to the target URL, that would have occurred by the time the event handler returns and the unused child view instance, is destroyed. What's more, users may also implement IResourceInterceptor and cancel requests to new views that are the result of JavaScript window.open (see IsWindowOpen). Therefore, if your application chooses to wrap the created child view even though it is most possibly the result of a user clicking on a link with target="_blank" or navigation to the target URL has already been canceled by an IResourceInterceptor (see IsNavigationCanceled), you should in this scenario only, after wrapping the child view, set the Source property to TargetURL to resume navigation to the target URL.
    Note Note
    Applications can occasionally choose to wrap a child view even when IsWindowOpen is false or IsNavigationCanceled is true, if they want to apply a single process architecture where all new views created will be rendered by the same awesomium_process.
  • When IsWindowOpen is true, Specs returns a valid, initialized JSWindowOpenSpecs instance. This may be initialized to default values if IsPopup is false, or reflect the specs specified to the window.open call, if IsPopup is true.
  • If IsPopup is true, applications should generally wrap and present the native view in a new popup application window. This window should have the size and location specified in InitialPosition, if this is not empty. They should also respect the rest of the specs available through Specs, when creating the new application window that will host the child view.
    Note Note
    When IsPopup is true, IsWindowOpen is always also true.
  • IsPopup will only be true, if specs were specified to the window.open call. These can be standard specs such as width=400,height=400,menubar=no, only user defined, non-standard specs such as background=black or a combination of both. These specs are available through the Specs property.
  • If only user defined, non-standard specs were specified to the window.open call, IsUserSpecsOnly will be true. In this scenario, if your application does not recognize user defined, non-standard specs, it can ignore the value of IsPopup all together and wrap the new child view in a regular new application window, tab or control.
  • When IsPost is true, PostData returns an array of UploadElement, representing the upload data passed to the TargetURL using POST.
  • Finally note that only an empty name parameter or a _blank target attribute specified as the name parameter in a window.open call or in a link or form, will fire a ShowCreatedWebView event. Other target attributes (such as _top), passed to either a window.open call, a link or a form, are handled by Awesomium internally.
Caution note Caution
Several members of ShowCreatedWebViewEventArgs, may not return valid values if Javascript is disabled. For details, read the documentation of: IsJavascriptEnabled.
Given the facts and suggestions presented before, if your application is about to wrap the created child view, the following table shows the methods available, to wrap the created child view using any of the Awesomium.NET web-view components:
Technology Method and Notes
Core
WPF
  • Create a new WebControl and assign NewViewInstance to the NativeView property.
    Note Note
    Note that you should assign the created child view instance to NativeView, before the WebControl goes live (see IsLive), or else the WebControl will create and wrap a new, underlying web-view instance. The appropriate way to do this, is either by binding the NativeView property in XAML (see examples in the Awesomium.NET Samples solution available with the SDK), or by monitoring the InitializeView event, the last fired before the control goes live.
  • Resize the WebControl or its container.
Windows Forms
  • Create a new WebControl and assign NewViewInstance to the NativeView property.
    Note Note
    Note that you should assign the created child view instance to NativeView, before the WebControl goes live (see IsLive), or else the WebControl will create and wrap a new, underlying web-view instance. The appropriate way to do this, is either by assigning the NativeView property right after the WebControl is created (see examples in the Awesomium.NET Samples solution available with the SDK),or by monitoring the InitializeView event, the last fired before the control goes live.
  • Resize the WebControl or its container.
Examples

The following example illustrates handling the ShowCreatedWebView event in a WPF application that uses WebControl controls. In this example, we create a ChildWindow window that hosts a WebControl. This window and its hosted WebControl will be used to wrap and present the child view passed to ShowCreatedWebView, or navigate to the target URL, if ShowCreatedWebView is the result of a link with target="_blank".

Below is the XAML of our ChildWindow.

XAML
<Window 
    x:Class="WebControlSample.ChildWindow" 
    x:Name="childWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:awe="http://schemas.awesomium.com/winfx"
    Title="{Binding Title, ElementName=webControl}" 
    Height="480" 
    Width="600">
    <Window.Resources>
        <!-- We do not need to set any WebPreferences or DataSources 
        on this provider. It uses the same DataPath as the provider in
        MainWindow, therefore, this provider will provide the same session,
        already created by the WebSessionProvider in MainWindow. -->
        <awe:WebSessionProvider x:Key="mySession" DataPath=".\Cache" />
    </Window.Resources>
    <Grid>
        <!-- Note that the WebSession assigned to this WebControl, will
             be effectively ignored when this WebControl wraps a created
             child view. Child views share the same session as their parent
             (opener) view. -->
        <awe:WebControl 
            Name="webControl" 
            WebSession="{Binding Source={StaticResource mySession}}"
            Source="{Binding Source, ElementName=childWindow}"
            NativeView="{Binding NativeView, ElementName=childWindow}" />
    </Grid>
</Window>
This is the code-behind of the ChildWindow:
using System;
using System.Linq;
using System.Windows;
using Awesomium.Core;
using System.Collections.Generic;

namespace WebControlSample
{
    /// <summary>
    /// Interaction logic for ChildWindow.xaml
    /// </summary>
    public partial class ChildWindow : Window
    {
        public ChildWindow()
        {
            InitializeComponent();

            // In this example, ShowCreatedWebView of all WebControls, 
            // is handled by a common handler.
            webControl.ShowCreatedWebView += App.OnShowNewView;
        }

        protected override void OnClosed( EventArgs e )
        {
            base.OnClosed( e );

            // Destroy the WebControl and its underlying view.
            webControl.Dispose();
        }

        // This will be set to the target URL, when this ChildWindow does not
        // host a created child view. The WebControl, is bound to this property.
        public Uri Source
        {
            get { return this.GetValue( SourceProperty ) as Uri; }
            set { SetValue( SourceProperty, value ); }
        }

        public static readonly DependencyProperty SourceProperty = 
            DependencyProperty.Register( "Source",
            typeof( Uri ), typeof( ChildWindow ),
            new UIPropertyMetadata( null ) );

        // This will be set to the created child view that the WebControl will wrap,
        // when ShowCreatedWebView is the result of 'window.open'. The WebControl, 
        // is bound to this property.
        public IntPtr NativeView
        {
            get { return (IntPtr)this.GetValue( ChildWindow.NativeViewProperty ); }
            internal set { this.SetValue( ChildWindow.NativeViewPropertyKey, value ); }
        }

        private static readonly DependencyPropertyKey NativeViewPropertyKey = 
            DependencyProperty.RegisterReadOnly( "NativeView",
            typeof( IntPtr ), typeof( ChildWindow ),
            new FrameworkPropertyMetadata( IntPtr.Zero ) );

        public static readonly DependencyProperty NativeViewProperty =
            NativeViewPropertyKey.DependencyProperty;

    }
}
Below is the common ShowCreatedWebView handler, defined in our Application object code-behind:
using System;
using System.Linq;
using System.Windows;
using Awesomium.Core;
using System.Collections.Generic;
using Awesomium.Windows.Controls;

namespace WebControlSample
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private void Application_Exit( object sender, ExitEventArgs e )
        {
            // Shutdown the Core.
            WebCore.Shutdown();
        }

        // This static handler, will handle the ShowCreatedWebView event for both the 
        // WebControl of our main application window, as well as for any other windows
        // hosting WebControls.
        internal static void OnShowNewView( object sender, ShowCreatedWebViewEventArgs e )
        {
            WebControl webControl = sender as WebControl;

            if ( webControl == null )
                return;

            if ( !webControl.IsLive )
                return;

            // Create an instance of our application's child window, that will
            // host the new view instance, either we wrap the created child view,
            // or we let the WebControl create a new underlying web-view.
            ChildWindow newWindow  = new ChildWindow();

            // Treat popups differently. If IsPopup is true, the event is always
            // the result of 'window.open' (IsWindowOpen is also true, so no need to check it).
            // Our application does not recognize user defined, non-standard specs. 
            // Therefore child views opened with non-standard specs, will not be presented as 
            // popups but as regular new windows (still wrapping the child view however -- se below).
            if ( e.IsPopup && !e.IsUserSpecsOnly )
            {
                // JSWindowOpenSpecs.InitialPosition indicates screen coordinates.
                Int32Rect screenRect = e.Specs.InitialPosition.GetInt32Rect();

                // Set the created native view as the underlying view of the
                // WebControl. This will maintain the relationship between
                // the parent view and the child, usually required when the new view
                // is the result of 'window.open' (JS can access the parent window through
                // 'window.opener'; the parent window can manipulate the child through the 'window'
                // object returned from the 'window.open' call).
                newWindow.NativeView = e.NewViewInstance;
                // Do not show in the taskbar.
                newWindow.ShowInTaskbar = false;
                // Set a border-style to indicate a popup.
                newWindow.WindowStyle = System.Windows.WindowStyle.ToolWindow;
                // Set resizing mode depending on the indicated specs.
                newWindow.ResizeMode = e.Specs.Resizable ? ResizeMode.CanResizeWithGrip : ResizeMode.NoResize;

                // If the caller has not indicated a valid size for the new popup window,
                // let it be opened with the default size specified at design time.
                if ( ( screenRect.Width > 0 ) && ( screenRect.Height > 0 ) )
                {
                    // Assign the indicated size.
                    newWindow.Width = screenRect.Width;
                    newWindow.Height = screenRect.Height;
                }

                // Show the window.
                newWindow.Show();

                // If the caller has not indicated a valid position for the new popup window,
                // let it be opened in the default position specified at design time.
                if ( ( screenRect.Y > 0 ) && ( screenRect.X > 0 ) )
                {
                    // Move it to the indicated coordinates.
                    newWindow.Top = screenRect.Y;
                    newWindow.Left = screenRect.X;
                }
            }
            else if ( e.IsWindowOpen || e.IsPost )
            {
                // No specs or only non-standard specs were specified, but the event is still 
                // the result of 'window.open', or of an HTML form with tagret="_blank" and method="post". 
                // We will open a normal window but we will still wrap the new native child view, 
                // maintaining its relationship with the parent window.
                newWindow.NativeView = e.NewViewInstance;
                // Show the window.
                newWindow.Show();
            }
            else
            {
                // The event is not the result of 'window.open' or of an HTML form with tagret="_blank" 
                // and method="post"., therefore it's most probably the result of a link with target='_blank'.
                // We will not be wrapping the created view; we let the WebControl hosted in ChildWindow 
                // create its own underlying view. Setting Cancel to true tells the core to destroy the 
                // created child view.
                // 
                // Why don't we always wrap the native view passed to ShowCreatedWebView?
                // 
                // - In order to maintain the relationship with their parent view,
                // child views execute and render under the same process (awesomium_process)
                // as their parent view. If for any reason this child process crashes,
                // all views related to it will be affected. When maintaining a parent-child 
                // relationship is not important, we prefer taking advantage of the isolated process 
                // architecture of Awesomium and let each view be rendered in a separate process.
                e.Cancel = true;
                // Note that we only explicitly navigate to the target URL, when a new view is 
                // about to be created, not when we wrap the created child view. This is because 
                // navigation to the target URL (if any), is already queued on created child views. 
                // We must not interrupt this navigation as we would still be breaking the parent-child
                // relationship.
                newWindow.Source = e.TargetURL;
                // Show the window.
                newWindow.Show();
            }
        }
    }
}
For the complete sample, see the C# WebControlSample of the Awesomium.NET Samples solution, available with the SDK.
See Also

Reference