どうやら、 WPF WebBrowser コントロールにはキーボードとフォーカスに関する重大な問題がいくつかあるようです。WebBrowser と 2 つのボタンだけの簡単な WPF アプリを作成しました。アプリは非常に基本的な編集可能な HTML マークアップ ( <body contentEditable='true'>some text</body>
) を読み込み、次のことを示します。
タブ操作は不適切です。ユーザーは、Tab を 2 回押して WebBrowser 内のキャレット (テキスト カーソル) を表示し、入力できるようにする必要があります。
ユーザーがアプリから離れて (Alt-Tab などで) 切り替えてから戻ると、キャレットがなくなり、まったく入力できなくなります。キャレットとキーストロークを元に戻すには、WebBrowser のウィンドウ クライアント領域をマウスで物理的にクリックする必要があります。
一貫性がなく、点線のフォーカス四角形が WebBrowser の周囲に表示されます (タブ移動時は表示されますが、クリック時は表示されません)。私はそれを取り除く方法を見つけることができませんでした (
FocusVisualStyle="{x:Null}"
助けにはなりません)。内部的には、WebBrowser がフォーカスを受け取ることはありません。これは、論理フォーカス ( FocusManager ) と入力フォーカス ( Keyboard )の両方に当てはまります。
Keyboard.GotKeyboardFocusEvent
およびFocusManager.GotFocusEvent
イベントは、WebBrowser に対して発生することはありません (ただし、どちらも同じフォーカス スコープ内のボタンに対して発生します)。キャレットが WebBrowser 内にある場合でも、以前にフォーカスされた要素 (ボタン)をFocusManager.GetFocusedElement(mainWindow)
指し、. 同時に、 を返します。Keyboard.FocusedElement
null
((IKeyboardInputSink)this.webBrowser).HasFocusWithin()
true
私は、そのような行動はほとんど機能不全であり、真実ではないと言いますが、それがどのように機能するかです. 私はおそらくそれを修正するためのいくつかのハックを考え出し、TextBox
. それでも、ここであいまいでありながら単純なものが欠けている可能性があることを願っています。誰かが同様の問題に対処しましたか?これを修正する方法についての提案は大歓迎です。
この時点で、 HwndHostに基づいて、WebBrowser ActiveX コントロール用の社内 WPF ラッパーを開発する傾向があります。また、Chromium Embedded Framework (CEF) など、WebBrowser に代わるものも検討しています。
VS2012 プロジェクトは、誰かが試してみたい場合に備えて、ここからダウンロードできます。
これは 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>
これは C# コードです。フォーカス/キーボード イベントがどのようにルーティングされ、フォーカスがどこにあるかを示す一連の診断トレースがあります。
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;
}
}
}
[更新] WinForms WebBrowserを (WPF WebBrowser の代わりに、または 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>
唯一の改善点は、フォーカス イベントが表示されることWindowsFormsHost
です。
[更新]極端なケース: 2 つのキャレットを同時に表示する 2 つの 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"/>
<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>");
これは、フォーカス処理の問題がコンテンツに固有のものではないことも示していcontentEditable=true
ます。