WPF comes with a WebBrowser control. When we use it to open a webpage, such as Baidu, and then click a link in it, a new window will pop up, then it will pop up an IE window instead of jumping to the link internally.
If you use the WebBrowser control of Winform, we can listen to its NewWindow event and perform some processing in this event. For example, when you create a new Tab to open it, you can also control the redirection in the current WebBrowser. Unfortunately, the WPF WebBrowser does not have this event.
In the end, Winform's WB or wpf wb are all calling a control of IE. Therefore, we can add Winform, and WPF must also have a way to add it. In this case, let's take a look at the Reflector.
First, open WebBrowser of Winform and find the code that triggers the NewWindow event:
Protected virtual void OnNewWindow (CancelEventArgs e)
{
If (this. NewWindow! = Null)
{
This. NewWindow (this, e );
}
}
It is triggered in the OnNewWindow method. So who called this OnNewWindow? Then, search for the result and find the following section in a class called WebBrowserEvent:
Public void NewWindow2 (ref object ppDisp, ref bool cancel)
{
CancelEventArgs e = new CancelEventArgs ();
This. parent. OnNewWindow (e );
Cancel = e. Cancel;
}
We searched NewWindow2, but found that it was called explicitly without any location. Since the method is not found, let's look at the WebBrowserEvent defining this method to see who is using it.
Search carefully and find the following section in the CreateSink method of WebBrowser:
Code
Protected override void CreateSink ()
{
Object activeXInstance = base. activeXInstance;
If (activeXInstance! = Null)
{
This. webBrowserEvent = new WebBrowserEvent (this );
This. webBrowserEvent. AllowNavigation = this. AllowNavigation;
This. cookie = new AxHost. ConnectionPointCookie (activeXInstance, this. webBrowserEvent, typeof (UnsafeNativeMethods. DWebBrowserEvents2 ));
}
}
Note this sentence:
This. cookie = new AxHost. ConnectionPointCookie (activeXInstance, this. webBrowserEvent, typeof (UnsafeNativeMethods. DWebBrowserEvents2 ));
Obviously, this sentence is the key. The role of the AxHost. ConnectionPointCookie class is to "connect an ActiveX control to the client that handles the events of the control ".
There is a very strange type in the above call: DWebBrowserEvents2. It should be ready to come up with COM, which is actually a definition of the COM type.
Code
[ComImport, TypeLibType (TypeLibTypeFlags. FHidden), InterfaceType (ComInterfaceType. InterfaceIsIDispatch), Guid ("34A715A0-6587-11D0-924A-0020AFC7AC4D")]
Public interface DWebBrowserEvents2
{
......
}
In fact, let's look at the definition of WebBrowserEvent, which implements this interface.
[ClassInterface (ClassInterfaceType. None)]
Private class WebBrowserEvent: standardoleexternalobject, UnsafeNativeMethods. DWebBrowserEvents2
{
......
}
Therefore, the above sentence is not hard to understand, that is, to define a type that implements a specific COM interface, so that browser control events can be forwarded to this type of instance for processing. Therefore, NewWindow2 is actually called by browser controls.
We have figured out the WebBrowser of Winform. Let's take a look at WPF. In fact, after opening the WPF WebBrowser code, we will find that it is the same as the WebBrowser mechanism of Winform. A familiar CreateSink method comes into the eyes:
Code
[SecurityTreatAsSafe, SecurityCritical]
Internal override void CreateSink ()
{
This. _ cookie = new ConnectionPointCookie (this. _ axIWebBrowser2, this. _ hostingAdaptor. CreateEventSink (), typeof (UnsafeNativeMethods. DWebBrowserEvents2 ));
}
There is also a ConnectionPointCookie, but its access permission is internal :(
The second parameter, _ hostingAdapter. CreateEventSink, returns the following information:
Code
[SecurityCritical]
Internal virtual object CreateEventSink ()
{
Return new WebBrowserEvent (this. _ webBrowser );
}
[ClassInterface (ClassInterfaceType. None)]
Internal class WebBrowserEvent: InternalDispatchObject <UnsafeNativeMethods. DWebBrowserEvents2>, UnsafeNativeMethods. DWebBrowserEvents2
{
......
}
It is still a WebBrowserEvent! The tragedy is that this WPF WebBrowserEvent does not trigger newjavaswevent:
Public void NewWindow2 (ref object ppDisp, ref bool cancel)
{
}
Now I know why the WB control of WPF has no NewWindow event? Microsoft's kids shoes haven't been written!
Since Microsoft's kids shoes are not written, let's make a hard effort on our own. The principle is already clear.
First, we have to define a DWebBrowserEvents2 interface, so we can copy it directly through Reflector. The code is not pasted.
Next, let's create another WebBrowserEvent. The key is to trigger the NewWindow event:
Code
Public partial class WebBrowserHelper
{
Private class WebBrowserEvent: standardoleexternalobject, DWebBrowserEvents2
{
Private WebBrowserHelper _ helperInstance = null;
Public WebBrowserEvent (WebBrowserHelper helperInstance)
{
_ HelperInstance = helperInstance;
}
......
Public void NewWindow2 (ref object pDisp, ref bool cancel)
{
_ HelperInstance. OnNewWindow (ref cancel );
}
......
}
}
Finally, we need to copy the code in the Framework and use CreateSink (I admit, using reflection to retrieve the internal stuff in WebBrowser, who makes these types all internal ):
Code
Private void Attach ()
{
Var axIWebBrowser2 = _ webBrowser. ReflectGetProperty ("AxIWebBrowser2 ");
Var webBrowserEvent = new WebBrowserEvent (this );
Var cookieType = typeof (WebBrowser). Assembly. GetType ("MS. Internal. Controls. ConnectionPointCookie ");
_ Cookie = Activator. CreateInstance (
CookieType,
ReflectionService. BindingFlags,
Null,
New [] {axIWebBrowser2, webBrowserEvent, typeof (DWebBrowserEvents2 )},
CultureInfo. CurrentUICulture );
}
Last use:
Var webBrowserHelper = new WebBrowserHelper (webBrowser );
......
WebBrowserHelper. NewWindow + = WebBrowserOnNewWindow;
【]
Initial webpage:
Click a link. By default, an IE window is displayed, which is opened in the new Tab:
[Sample Code]
(After clicking the new button, enter the complete URL, such as: http://www.sina.com)
/Files/RMay/WpfWebBrowser.zip