WPF: jak programowo usunąć fokus z TextBox

96

Chcę dodać proste (przynajmniej tak mi się wydawało) zachowanie do mojego WPF TextBox.

Kiedy użytkownik naciśnie klawisz Escape, chcę TextBox, aby edytowany przez niego tekst miał tekst, który miał, gdy użytkownik zaczął edytować, ORAZ chcę usunąć fokus z TextBox.

Nie mam żadnego problemu z ustawieniem tekstu na wartość, którą miał na początku edycji.

Problem polega na usunięciu skupienia elementu. Nie chcę przenosić fokusu na żaden inny komponent, chcę tylko, TextBoxaby stracił fokus. Czy będę musiał mieć niewidzialny element, aby ustawić ostrość, aby moja TextBoxmogła stracić koncentrację?

jpsstavares
źródło

Odpowiedzi:

153

w .NET Framework 4 Keyboard.ClearFocus();

LPL
źródło
1
Właśnie tego szukałem tego wieczoru!
Josh
9
Nie zawsze jest to jasne: mam problem polegający na tym, że AutoCompleteTextBox wewnątrz ListBox nie traci ostrości, gdy uruchamiam Keyboard.ClearFocus()z kodu źródłowego po kliknięciu gdzieś.
ANeves uważa, że ​​SE jest zła.
3
ClearFocuspowoduje, GotFocusże nie uruchamia się dla ostatnio nastawionej kontroli, podczas gdy nadal strzela do innych kontrolek. Na przykład to duży problem z moją niestandardową klawiaturą ekranową. Powoduje to zniknięcie znaku daszka, co jest prawdopodobnie wszystkim, co pociąga za sobą „fokus klawiatury”. Może bardziej interesuje mnie coś w rodzaju „skupienia myszy”.
Grault
3
Dziękuję Grault, mam ten sam problem. Najlepsze, co wymyśliłem, to przeniesienie uwagi na inną kontrolę other.Focus().
Tor Klingberg
7
@Grault To tylko czyści fokus klawiatury, a nie logiczny fokus (który jest tym, co uruchamia GotFocuszdarzenie). W programie zawsze jest coś, co jest logiczne. Użyj LostKeyboardFocuszdarzenia lub przenieś fokus na inny element (który przesuwa logiczny fokus wraz z nim) przed wyczyszczeniem fokusa klawiatury.
Chirimorin,
56

Kod, którego używałem:

// 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);
decasteljau
źródło
2
Ten kod jest świetny, Keyboard.ClearFocus () ma pewne niezamierzone efekty uboczne
patrick
Dlaczego warunek! ((IInputElement) rodzic) .Focusable ma znak „!” z przodu? Czy ten warunek nie powinien być prawdziwy, jeśli rodzic może się skupić?
Mert Akcakaya
Mert - nie jestem pewien, ale po prostu przeglądając ten post wygląda na to, że kontynuuje pętlę, dopóki ten warunek nie będzie prawdziwy. W ten sposób pierwszy element, który można zaznaczyć, kończy pętlę.
jpierson
4
@patrick, jakie niezamierzone efekty uboczne? Czy mógłbyś podać odpowiednie przykłady?
ANeves uważa, że ​​SE jest złem
2
To świetne rozwiązanie. Miałem też problemy z Keyboard.ClearFocus (). Uruchamianie ClearFocus () na TextBox wewnątrz modalnego okna powoduje utratę fokusu zarówno TextBox, jak i Window. Oznacza to, że zdarzenia KeyDown nie są już wyświetlane w oknie. Zamiast tego zmieniając to tak, aby Fokus zmienił się na rodzica (którym może być Okno), przyszłe zdarzenia KeyDown nie zostaną utracone. W moim praktycznym przykładzie okno wyszukuje „Key.Escape” i wywołuje funkcję Close (). To przestaje działać, jeśli uruchomisz ClearFocus () w dowolnym miejscu.
Denis P,
19

Trochę za późno na imprezę, ale mi pomogło, więc proszę bardzo.

Od .Net 3.0 FrameworkElementma funkcję MoveFocus, która załatwiła mi sprawę .

SuperOli
źródło
Instrukcje -> msdn.microsoft.com/en-us/library/…
Carter Medlin
„Upewnij się, że sprawdzasz wartość zwracaną przez tę metodę. Wartość zwracana false może zostać zwrócona, jeśli przechodzenie napotka pozycję tabulacji zdefiniowaną przez skład kontrolki, a żądanie przejścia nie zażądało zawinięcia”. - msdn.microsoft.com/en-us/library/ ...
aderesh
15

Ponieważ żadna z powyższych odpowiedzi nie zadziałała dla mnie, a zaakceptowana odpowiedź działa tylko dla fokusu klawiatury, doszedłem do następującego podejścia:

// Kill logical focus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
// Kill keyboard focus
Keyboard.ClearFocus();

Zabija zarówno logikę, jak i fokus klawiatury.

Cyklon
źródło
9

Możesz ustawić fokus na przodka, którego można fokusować. Ten kod będzie działał, nawet jeśli pole tekstowe znajduje się w szablonie bez przodków, których można fokusować w tym samym szablonie:

DependencyObject ancestor = textbox.Parent;
while (ancestor != null)
{
    var element = ancestor as UIElement;
    if (element != null && element.Focusable)
    {
        element.Focus();
        break;
    }

    ancestor = VisualTreeHelper.GetParent(ancestor);
}
Julian Dominguez
źródło
6

ODPOWIEDŹ, całkowite usunięcie ostrości nie jest możliwe. Coś w twoim oknie zawsze będzie się skupiało.

bitbonk
źródło
2

W programowaniu na Windows Phone właśnie zrobiłem Focus()lub this.Focus()na PhoneApplicationPage i działało to jak urok.

Bruno Lemos
źródło
1

Dla mnie jest to dość trudne, szczególnie w połączeniu z wiązaniem LostFocus. Jednak moim obejściem jest dodanie pustej etykiety i skupienie się na niej.

<Label Name="ResetFocusArea" Focusable="True" FocusVisualStyle="{x:Null}" />

...

OnKeyDown(object sender, RoutedEventArgs e)
{
  //if is Esc
  ResetFocusArea.Focus();
}
Brian Ng
źródło
0

Moja odpowiedź nie odnosi się bezpośrednio do powyższego pytania, jednak czuję, że jego brzmienie sprawiło, że stało się ono „pytaniem” o programowe pozbycie się koncentracji. Typowy scenariusz, w którym jest to potrzebne, polega na tym, że użytkownik może wyczyścić fokus po kliknięciu lewym przyciskiem myszy tła elementu sterującego głównego, takiego jak okno.

Aby to osiągnąć, możesz utworzyć dołączone zachowanie, które przełączy fokus na dynamicznie utworzoną kontrolkę (w moim przypadku pustą etykietę). Zaleca się używanie tego zachowania na elementach najwyższego poziomu, takich jak okna, ponieważ iteruje ono po swoich elementach potomnych, aby znaleźć panel, do którego może dodać fikcyjną etykietę.

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();
    }
}
TripleAccretion
źródło