Quick Tipp: Das WPF-WebBrowser-Control an die Leine legen

Eine der mit .NET Framework 3.5 SP1 eingeführten WPF-Erweiterungen ist die Klasse System.Windows.Controls.WebBrowser. Leider ist der Namespace etwas irreführend, da es sich hierbei nicht um ein normales WPF-Steuerelement mit Control Template und Content Model handelt, sondern nur (wie auch bei seinem engen Verwandten System.Windows.Forms.WebBrowser) um einen Wrapper um die COM-Schnittstellen des Internet Explorer. WPF-Features wie Styles oder das Anpassen des Control Templates sind also hierauf leider nicht anwendbar. Dies ist vor allem bei Scrollbars störend, die von WebBrowser selbst gezeichnet werden und u.U. komplett anders aussehen als Scrollbars in der WPF-Anwendung.

Wesentlich schwerwiegender als dieser optische Bruch ist jedoch die Tatsache, dass ein Anwender im WebBrowser-Control ein neues Internet Explorer-Fenster öffnen und somit aus der eigentlichen WPF-Applikation „ausbrechen“ kann. Gerade für Anwendungen, die in einem Kioskmodus laufen (d.h. die eigentliche Windows-Shell komplett verbergen), ist das Öffnen von fremden Anwendungsfenstern extrem störend.

Um solche Effekte bei der Verwendung von WebBrowser zu verhindern, muss man etwas tiefer bohren, da das Steuerelement keine Eigenschaften oder Methoden besitzt, die zum Beispiel das Öffnen eines neuen Fensters verhindern.

Öffnen eines neuen Fensters über Shortcuts verhindern

Da WebBrowser kein Hauptmenü, Tabs oder Toolbar mit sich bringt, verbleibt dem Anwender nur STRG+N zum Öffnen eines neuen Fensters. Dieser Shortcut lässt sich in WPF über das Tunneling-Event PreviewKeyDown unterbinden:

 <WebBrowser x:Name="webBrowser"
            LoadCompleted="webBrowser_LoadCompleted"
            MinWidth="400"
            MinHeight="400"
            PreviewKeyDown="webBrowser_PreviewKeyDown"
            Source="https://host/path/to/file.html" />

Das Tunneling-Event wird in dem Event-Handler als behandelt markiert, wenn die aktuelle gedrückte Tasten-Kombination  STRG (bzw. Control) und N entspricht.

 private void webBrowser_PreviewKeyDown(object sender, KeyEventArgs e)
{
    e.Handled = e.Key == Key.N && e.KeyboardDevice.Modifiers == ModifierKeys.Control;
}

Etwas kniffliger ist der Umgang mit HTML-Quellen, die von sich aus das Öffnen neuer Fenster erlauben, also Anchor-Elemente mit dem Attribut target="_blank".Hier hilft nur noch die direkte Manipulation des Browser-DOM — z.B. kann man für alle solche Anchor-Elemente "_blank" durch "_self" ersetzt:

 private void webBrowser_LoadCompleted(object sender, NavigationEventArgs e)
{
    HTMLDocumentClass doc = (HTMLDocumentClass) this.webBrowser.Document;
    IHTMLElementCollection all = (IHTMLElementCollection) doc.all;
    IHTMLElementCollection anchors = (IHTMLElementCollection) all.tags("A");
    foreach (HTMLAnchorElement a in anchors)
    {
        if (a.target.Equals("_blank", StringComparison.OrdinalIgnoreCase))
        {
            a.target = "_self";
        }
    }
}

Leider ist der Typ von WebBrowser.Document nur System.Object. Tatsächlich verbergen sich dahinter aber wie bereits erwähnt die COM-Schnittstellen des Internet Explorer. Auf diese kann man über die Interop-Assembly Microsoft.mshtml.dll zugreifen. Diese wird mit Visual Studio installiert und befindet sich unter %ProgramFiles%\Microsoft.NET\Primary Interop Assemblies. Die Namensgebung für die Typen in dieser Assembly mutet aufgrund der COM-Historie für .NET-Entwickler etwas seltsam an. Faustregel: Die mit FooClass bezeichneten Typen implementieren die Schnittstellen IFoo bis IFooN. Die Dokumentation dieser Typen findet man übrigens auf MSDN unter Internet Explorer Development.

Ausblick

Die hier gezeigten Eingriffe reichen unter Umständen nicht aus — dynamisch erzeugte DOM-Elemente sowie JavaScript können noch immer neue Fenster öffnen. Über die MSHTML-API kann man aber hier bei Bedarf noch tiefer in das Browser-Control eingreifen und DOM wie Script-Code nach Lust und Laune manipulieren.

Jörg