2024-02-02 (金)
[WPF] 現在のフォーカスを安心してクリアする方法
特定のタイミングでフォーカスを外す C# コードを説明します。
現在のフォーカスを外した際に、LostFocus
イベントも発生させます。フォーカスを外した後のキーボードフォーカスも正しく設定します。
環境
- .NET 8.0.100
- C# 12.0
- Visual Studio 2022 Version 17.8.5
- Windows 11 Pro 22H2 22621.3007
結果
✨ (推奨) Window で実装する場合
public sealed class MyWindow : Window
{
public void ResetFocus()
{
if (Keyboard.FocusedElement is DependencyObject focusedElement)
{
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(focusedElement), null);
}
Focus();
}
}
Window が確定しない場合
public static void ResetFocus()
{
if (Keyboard.FocusedElement is not DependencyObject focusedElement)
return;
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(focusedElement), null);
// 必ず Window が見つかるケースで実行することを前提とします
var window = focusedElement as Window ?? Window.GetWindow(focusedElement);
window!.Focus();
}
説明
フォーカスを外すには、論理フォーカスとキーボードフォーカスの両方をクリアする必要があります。
フォーカスの概要 - WPF .NET Framework | Microsoft Learn
- 論理フォーカスは、FocusManager.SetFocusedElement() でクリアします。
- キーボードフォーカスは、UIElement.Focus() で Window にフォーカスを設定します。
- ⚠️ Keyboard.ClearFocus() は使用しません!
- 必ず親ウィンドウにフォーカスを設定します。
まずは、論理フォーカスをクリアします。これにより、フォーカスがあるコントロールの LostFocus
イベントが発生するはずです。
// 例えば TextBox にフォーカスがある場合は、LostFocus イベントが発生するはずです
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(focusedElement), null);
次に、親ウィンドウにキーボードフォーカスを設定します。
親ウィンドウが分かっている場合や、次にフォーカスしたいコントロールが分かっている場合は、直接そのコントロールの Focus()
を呼んでも良いと思います。
// 必ず Window が見つかるケースで実行することを前提とします
var window = focusedElement as Window ?? Window.GetWindow(focusedElement);
window!.Focus();
Window に設定したい理由は、注意点で説明します。
注意点
キーボードフォーカスをクリアする際に、Keyboard.ClearFocus() は使用しません。
理由
- 本当に
Keyboard.FocusedElement
がnull
になってしまいます。 - フォーカスを失うため、
Window.KeyDown
などのキーイベントも発生しなくなります⚠️ - 通常 Window を表示すると
Keyboard.FocusedElement
はWindow
になるため、その動作に従います。
また、論理フォーカスとキーボードフォーカスの片方だけをクリアすると、正しくない動作になります。
例えば、TextBox にフォーカスがある状態で
FocusManager.SetFocusedElement()
で論理フォーカスのみクリアすると、LostFocus
が発生したのにキーカーソルが TextBox に残り、そのままキー入力が出来てしまう。Keyboard.ClearFocus()
でキーボードフォーカスのみクリアすると、LostFocus
が発生せず、キーカーソルが TextBox から消えてしまう。
というような動作になってしまいます。
感謝
関連記事
新着記事