WebBrowser steuert das Tastatur- und Fokusverhalten

Anscheinend gibt es einige ernsthafte Probleme mit der Tastatur und dem FokusWPF WebBrowser-Steuerelement. Ich habe eine einfache WPF-App zusammengestellt, nur einen Webbrowser und zwei Schaltflächen. Die App lädt ein sehr einfaches editierbares HTML-Markup (<body contentEditable='true'>some text</body>) und zeigt Folgendes:

Tabbing ist schlecht. Der Benutzer muss zweimal die Tabulatortaste drücken, um das Einfügemarke (den Textcursor) in WebBrowser zu sehen und tippen zu können.

Wenn der Benutzer von der App wegschaltet (z. B. mit Alt-Tab) und dann zurückgeht, ist das Caret weg und er kann überhaupt nichts mehr eingeben. Ein physischer Mausklick in den Client-Bereich des WebBrowsers ist erforderlich, um das Einfügemarke und die Tastatureingaben wiederherzustellen.

In uneinheitlicher Weise wird um WebBrowser ein gepunktetes Fokusrechteck angezeigt (beim Tabulator, aber nicht beim Klicken). Ich konnte keinen Weg finden, es loszuwerden (FocusVisualStyle="{x:Null}" hilft nicht).

Intern erhält WebBrowser nie den Fokus. Das gilt sowohl für den logischen Fokus (FocusManager) und Eingabefokus (Tastatur). DasKeyboard.GotKeyboardFocusEvent undFocusManager.GotFocusEvent Ereignisse werden für WebBrowser nie ausgelöst (obwohl beide für Schaltflächen ausgeführt werden)im gleichen Fokusbereich). Auch wenn das Caret in WebBrowser ist,FocusManager.GetFocusedElement(mainWindow) verweist auf ein zuvor fokussiertes Element (eine Schaltfläche) undKeyboard.FocusedElement istnull. Zur selben Zeit,((IKeyboardInputSink)this.webBrowser).HasFocusWithin() kehrt zurücktrue.

Ich würde sagen, ein solches Verhalten ist fast zu dysfunktional, um wahr zu sein, aber so funktioniert es. Ich könnte mir wahrscheinlich ein paar Hacks einfallen lassen, um das Problem zu beheben und es mit nativen WPF-Steuerelementen wie in Reihe zu bringenTextBox. Trotzdem hoffe ich, vielleicht fehlt mir hier etwas Obskures und Einfaches. Hat sich jemand mit einem ähnlichen Problem befasst? Vorschläge zur Behebung dieses Problems sind sehr willkommen.

An diesem Punkt bin ich geneigt, einen internen WPF-Wrapper für WebBrowser ActiveX Control zu entwickeln, auf dessen BasisHwndHost. Wir sind auchandere Alternativen in Betracht ziehen für WebBrowser, z. B. Chromium Embedded Framework (CEF).

Das VS2012-Projekt kann von heruntergeladen werdenHier falls jemand damit spielen will.

Dies ist XAML:

<Window x:Class="WpfWebBrowserTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Width="640" Height="480" Background="LightGray">

    <StackPanel Margin="20,20,20,20">
        <ToggleButton Name="btnLoad" Focusable="True" IsTabStop="True" Content="Load" Click="btnLoad_Click" Width="100"/>

        <WebBrowser Name="webBrowser" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="300"/>

        <Button Name="btnClose" Focusable="True" IsTabStop="True" Content="Close" Click="btnClose_Click" Width="100"/>
    </StackPanel>

</Window>

Dies ist C # -Code. Er enthält eine Reihe von Diagnoseprotokollen, die zeigen, wie Fokus- / Tastaturereignisse weitergeleitet werden und wo der Fokus liegt:

using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Navigation;

namespace WpfWebBrowserTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // watch these events for diagnostics
            EventManager.RegisterClassHandler(typeof(UIElement), Keyboard.PreviewKeyDownEvent, new KeyEventHandler(MainWindow_PreviewKeyDown));
            EventManager.RegisterClassHandler(typeof(UIElement), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(MainWindow_GotKeyboardFocus));
            EventManager.RegisterClassHandler(typeof(UIElement), FocusManager.GotFocusEvent, new RoutedEventHandler(MainWindow_GotFocus));
        }

        private void btnLoad_Click(object sender, RoutedEventArgs e)
        {
            // load the browser
            this.webBrowser.NavigateToString("<body contentEditable='true' onload='focus()'>Line 1<br>Line 3<br>Line 3<br></body>");
            this.btnLoad.IsChecked = true;
        }

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            // close the form
            if (MessageBox.Show("Close it?", this.Title, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                this.Close();
        }

        // Diagnostic events

        void MainWindow_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            Debug.Print("{0}, source: {1}, {2}", FormatMethodName(), FormatType(e.Source), FormatFocused());
        }

        void MainWindow_GotFocus(object sender, RoutedEventArgs e)
        {
            Debug.Print("{0}, source: {1}, {2}", FormatMethodName(), FormatType(e.Source), FormatFocused());
        }

        void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            Debug.Print("{0}, key: {1}, source: {2}, {3}", FormatMethodName(), e.Key.ToString(), FormatType(e.Source), FormatFocused());
        }

        // Debug output formatting helpers

        string FormatFocused()
        {
            // show current focus and keyboard focus
            return String.Format("Focus: {0}, Keyboard focus: {1}, webBrowser.HasFocusWithin: {2}",
                FormatType(FocusManager.GetFocusedElement(this)),
                FormatType(Keyboard.FocusedElement),
                ((System.Windows.Interop.IKeyboardInputSink)this.webBrowser).HasFocusWithin());
        }

        string FormatType(object p)
        {
            string result = p != null ? String.Concat('*', p.GetType().Name, '*') : "null";
            if (p == this.webBrowser )
                result += "!!";
            return result;
        }

        static string FormatMethodName()
        {
            return new StackTrace(true).GetFrame(1).GetMethod().Name;
        }

    }
}

[AKTUALISIEREN] Die Situation wird nicht besser, wenn ich hosteWinForms WebBrowser (anstelle von oder neben WPF WebBrowser):

<StackPanel Margin="20,20,20,20">
    <ToggleButton Name="btnLoad" Focusable="True" IsTabStop="True" Content="Load" Click="btnLoad_Click" Width="100"/>

    <WebBrowser Name="webBrowser" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="150" Margin="10,10,10,10"/>

    <WindowsFormsHost Name="wfHost" Focusable="True" Height="150" Margin="10,10,10,10">
        <wf:WebBrowser x:Name="wfWebBrowser" />
    </WindowsFormsHost>

    <Button Name="btnClose" Focusable="True" IsTabStop="True" Content="Close" Click="btnClose_Click" Width="100"/>
</StackPanel>

Die einzige Verbesserung ist, dass ich Fokusereignisse auf seheWindowsFormsHost.

[AKTUALISIEREN] Extremfall: Zwei WebBrowser-Steuerelemente mit zwei gleichzeitig angezeigten Einfügemarken:

<StackPanel Margin="20,20,20,20">
    <ToggleButton Name="btnLoad" Focusable="True" IsTabStop="True" Content="Load" Click="btnLoad_Click" Width="100"/>

    <WebBrowser Name="webBrowser" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="150" Margin="10,10,10,10"/>
    <WebBrowser Name="webBrowser2" Focusable="True" KeyboardNavigation.IsTabStop="True" FocusVisualStyle="{x:Null}" Height="150" Margin="10,10,10,10"/>

    <Button Name="btnClose" Focusable="True" IsTabStop="True" Content="Close" Click="btnClose_Click" Width="100"/>
</StackPanel>

this.webBrowser.NavigateToString("<body onload='text.focus()'><textarea id='text' style='width: 100%; height: 100%'>text</textarea></body>");
this.webBrowser2.NavigateToString("<body onload='text.focus()'><textarea id='text' style='width: 100%; height: 100%'>text2</textarea></body>");

Dies zeigt auch, dass das Problem der Fokusverwaltung nicht spezifisch istcontentEditable=true Inhalt.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage