WPF TextBox
に単純な(少なくとも私はそう思った)動作を追加したい。
ユーザーがEscapeを押すと、編集中のTextBox
に、ユーザーが編集を開始したときに持っていたテキストを持たせ、_TextBox
からフォーカスを削除したいです。
編集の開始時に持っていた値のテキストを設定するのに問題はありません。
問題は、要素のフォーカスを削除することです。他のコンポーネントにフォーカスを移動したくないので、TextBox
のフォーカスを失いたいだけです。 TextBox
がフォーカスを失うことができるように、フォーカスを設定するために非表示要素が必要ですか?
.NET Framework 4では Keyboard.ClearFocus();
私が使用しているコード:
// Move to a parent that can take focus
FrameworkElement parent = (FrameworkElement)textBox.Parent;
while (parent != null && parent is IInputElement && !((IInputElement)parent).Focusable)
{
parent = (FrameworkElement)parent.Parent;
}
DependencyObject scope = FocusManager.GetFocusScope(textBox);
FocusManager.SetFocusedElement(scope, parent as IInputElement);
パーティーに少し遅れましたが、私にとっては助かりました。
.Net 3.0以降、FrameworkElement
には MoveFocus 関数があり、これが私にとってはうまくいきました。
フォーカス可能な先祖にフォーカスを設定できます。このコードは、テキストボックスがテンプレート内にあり、同じテンプレート内にフォーカス可能な先祖がない場合でも機能します。
DependencyObject ancestor = textbox.Parent;
while (ancestor != null)
{
var element = ancestor as UIElement;
if (element != null && element.Focusable)
{
element.Focus();
break;
}
ancestor = VisualTreeHelper.GetParent(ancestor);
}
私の知る限り、フォーカスを完全に削除することはできません。ウィンドウ内の何かが常にフォーカスされます。
上記の答えはどれも私にとってはうまくいかず、受け入れられた答えはキーボードフォーカスに対してのみ機能するため、次のアプローチに至りました。
// Kill logical focus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
// Kill keyboard focus
Keyboard.ClearFocus();
論理的およびキーボードフォーカスの両方を強制終了します。
Windows Phone開発では、PhoneApplicationPageでFocus()
またはthis.Focus()
を実行しただけで、まるで魔法のように機能しました。
私にとっては、特にLostFocusバインディングで使用する場合、非常に注意が必要です。ただし、私の回避策は、空のラベルを追加し、それに注目することです。
<Label Name="ResetFocusArea" Focusable="True" FocusVisualStyle="{x:Null}" />
...
OnKeyDown(object sender, RoutedEventArgs e)
{
//if is Esc
ResetFocusArea.Focus();
}
私の答えは上記の質問を直接解決するものではありませんが、その言葉遣いがプログラムによって焦点を取り除くことについての「質問」になったと感じています。これが必要な一般的なシナリオは、ユーザーがウィンドウなどのルートコントロールの背景を左クリックしてフォーカスをクリアできるようにすることです。
そのため、これを実現するために、動的に作成されたコントロール(私の場合は空のラベル)にフォーカスを切り替える添付ビヘイビアーを作成できます。ウィンドウなどの最上位要素でこの動作を使用することをお勧めします。これは、子を反復処理してダミーラベルを追加できるパネルを見つけるためです。
public class LoseFocusOnLeftClick : Behavior<FrameworkElement>
{
private readonly MouseBinding _leftClick;
private readonly Label _emptyControl = new Label() { Focusable = true, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top };
public LoseFocusOnLeftClick()
{
_leftClick = new MouseBinding(new RelayCommand(LoseFocus), new MouseGesture(MouseAction.LeftClick));
}
protected override void OnAttached()
{
AssociatedObject.InputBindings.Add(_leftClick);
AssociatedObject.Loaded += AssociatedObject_Loaded;
}
protected override void OnDetaching()
{
AssociatedObject.InputBindings.Remove(_leftClick);
AssociatedObject.Loaded -= AssociatedObject_Loaded;
}
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
AssociatedObject.Loaded -= AssociatedObject_Loaded;
AttachEmptyControl();
}
private void AttachEmptyControl()
{
DependencyObject currentElement = AssociatedObject;
while (!(currentElement is Panel))
{
currentElement = VisualTreeHelper.GetChild(currentElement, 0);
}
((Panel)currentElement).Children.Add(_emptyControl);
}
private void LoseFocus()
{
_emptyControl.Focus();
}
}