Klawiatura sterująca WebBrowser i zachowanie fokusa

Najwyraźniej są pewne poważne problemy z klawiaturą i skupieniemKontrola WPF WebBrowser. Przygotowałem trywialną aplikację WPF, po prostu WebBrowser i dwa przyciski. Aplikacja ładuje bardzo prosty edytowalny znacznik HTML (<body contentEditable='true'>some text</body>) i pokazuje, co następuje:

Tabbing jest niewłaściwy. Użytkownik musi dwukrotnie nacisnąć Tab, aby zobaczyć kursor (kursor tekstowy) wewnątrz WebBrowser i móc pisać.

Gdy użytkownik przełącza się z aplikacji (np. Za pomocą Alt-Tab), następnie wraca, karetka zniknęła, a ona nie może w ogóle pisać. Fizyczne kliknięcie myszką w obszarze roboczym okna WebBrowser jest wymagane, aby odzyskać kursor i naciśnięcia klawiszy.

Niespójnie, wokół WebBrowser pojawia się prostokąt z przerywaną ostrością (podczas zakładania, ale nie po kliknięciu). Nie mogłem znaleźć sposobu, aby się go pozbyć (FocusVisualStyle="{x:Null}" nie pomaga).

Wewnętrznie WebBrowser nigdy nie otrzymuje fokusu. To prawda zarówno dla logicznego skupienia (FocusManager) i fokus wejściowy (Klawiatura). TheKeyboard.GotKeyboardFocusEvent iFocusManager.GotFocusEvent zdarzenia nigdy nie zostaną wystrzelone do WebBrowser (chociaż oba dotyczą przycisków)w tym samym zakresie ostrości). Nawet gdy daszek jest w WebBrowser,FocusManager.GetFocusedElement(mainWindow) wskazuje na wcześniej skupiony element (przycisk) iKeyboard.FocusedElement jestnull. W tym samym czasie,((IKeyboardInputSink)this.webBrowser).HasFocusWithin() zwracatrue.

Powiedziałbym, że takie zachowanie jest prawie zbyt dysfunkcyjne, aby mogło być prawdziwe, ale tak to działa. Prawdopodobnie mógłbym wymyślić kilka hacków, aby to naprawić i ustawić w wierszu z rodzimymi kontrolkami WPF takimi jakTextBox. Nadal mam nadzieję, że może brakuje mi tutaj czegoś niezrozumiałego, ale prostego. Czy ktoś zajmował się podobnym problemem? Wszelkie sugestie, jak to naprawić, byłyby bardzo mile widziane.

W tym momencie jestem skłonny opracować wewnętrzny wrapper WPF dla WebBrowser ActiveX ControlHwndHost. My też jesteśmyrozważając inne alternatywy do WebBrowser, takiego jak Chromium Embedded Framework (CEF).

Projekt VS2012 można pobrać ztutaj w przypadku, gdy ktoś chce się nim bawić.

To jest 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>

To jest kod C #, ma on kilka śladów diagnostycznych, aby pokazać, w jaki sposób zdarzenia fokusa / klawiatury są kierowane i gdzie skupia się:

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;
        }

    }
}

[AKTUALIZACJA] Sytuacja nie poprawia się, gdy go przyjmujęWinForms WebBrowser (zamiast lub obok siebie z 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>

Jedynym ulepszeniem jest to, że widzę zdarzenia fokusoweWindowsFormsHost.

[AKTUALIZACJA] Ekstremalny przypadek: dwie kontrolki WebBrowser z dwoma karnetami wyświetlanymi w tym samym czasie:

<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>");

Pokazuje to również, że problem z obsługą fokusa nie jest specyficznycontentEditable=true zawartość.

questionAnswers(2)

yourAnswerToTheQuestion