WPF: So entfernen Sie programmgesteuert den Fokus aus einer TextBox

95

Ich möchte meinem WPF ein einfaches Verhalten hinzufügen (zumindest dachte ich, dass es das ist) TextBox.

Wenn der Benutzer die Esc-Taste drückt TextBox, soll der Text, den er bearbeitet, den Text enthalten, den er zu Beginn der Bearbeitung hatte, UND ich möchte den Fokus aus dem entfernen TextBox.

Ich habe kein Problem damit, den Text auf den Wert einzustellen, den er zu Beginn der Bearbeitung hatte.

Das Problem besteht darin, den Fokus des Elements zu entfernen. Ich möchte den Fokus nicht auf eine andere Komponente verschieben, sondern nur den TextBoxFokus verlieren. Muss ich ein unsichtbares Element haben, um den Fokus einzustellen, damit ich TextBoxden Fokus verlieren kann?

jpsstavares
quelle

Antworten:

151

in .NET Framework 4 nur Keyboard.ClearFocus();

LPL
quelle
1
Genau das habe ich heute Abend gesucht!
Josh
9
Dies macht den Fokus nicht immer klar: Ich habe ein Problem, bei dem eine AutoCompleteTextBox in einer ListBox nicht den Fokus verliert, wenn ich Keyboard.ClearFocus()nach einem Klick irgendwo von CodeBehind aus laufe .
ANeves
3
ClearFocusbewirkt GotFocus, dass die kürzlich fokussierte Steuerung nicht ausgelöst wird, während sie weiterhin für andere Steuerelemente ausgelöst wird. Das ist zum Beispiel ein großes Problem für meine benutzerdefinierte Bildschirmtastatur. Es führt dazu, dass das Caret verschwindet, was wahrscheinlich alles ist, was "Tastaturfokus" mit sich bringt. Vielleicht interessiert mich mehr etwas wie "Mausfokus".
Grault
2
Danke Grault, ich habe das gleiche Problem. Das Beste, was ich mir ausgedacht habe, ist, mich auf eine andere Steuerung zu konzentrieren other.Focus().
Tor Klingberg
7
@Grault Hiermit wird nur der Tastaturfokus gelöscht, nicht der logische Fokus (der für das GotFocusEreignis ausgelöst wird ). Es gibt immer etwas mit logischem Fokus in Ihrem Programm. Verwenden Sie entweder das LostKeyboardFocusEreignis oder verschieben Sie den Fokus auf ein anderes Element (wodurch auch der logische Fokus verschoben wird), bevor Sie den Tastaturfokus löschen.
Chirimorin
54

Der Code, den ich verwendet habe:

// 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
quelle
2
Dieser Code ist großartig, Keyboard.ClearFocus () hat einige unbeabsichtigte Nebenwirkungen
Patrick
Warum die Bedingung! ((IInputElement) Eltern) .Focusable haben "!" vor? Sollte diese Bedingung nicht zutreffen, wenn die Eltern fokussierbar sind?
Mert Akcakaya
Mert - nicht sicher, aber wenn Sie nur diesen Beitrag durchsuchen, sieht es so aus, als würden Sie die Schleife fortsetzen, bis diese Bedingung erfüllt ist. Auf diese Weise beendet das erste fokussierbare Element die Schleife.
Jpierson
@Mert - Wenn das übergeordnete Element nicht fokussierbar ist, wird das übergeordnete Element in der Schleife auf das übergeordnete Element des übergeordneten Elements gesetzt. An dem Punkt, an dem das übergeordnete Element fokussierbar ist, stoppt die Schleife und das übergeordnete Element wird fokussiert.
Junichiro
4
@patrick, welche unbeabsichtigten Nebenwirkungen? Können Sie relevante Beispiele nennen?
ANeves
19

Ein bisschen spät zur Party, aber es war hilfreich für mich, also los geht's.

Seit .Net 3.0 FrameworkElementhat eine MoveFocus- Funktion, die den Trick für mich getan hat.

SuperOli
quelle
Für Anweisungen -> msdn.microsoft.com/en-us/library/…
Carter Medlin
"Stellen Sie sicher, dass Sie den Rückgabewert dieser Methode überprüfen. Ein Rückgabewert von false wird möglicherweise zurückgegeben, wenn der Traversal auf einen Tabulator stößt, der durch die Zusammensetzung eines Steuerelements definiert ist, und die Traversal-Anforderung keinen Wrap anfordert." - msdn.microsoft.com/en-us/library/…
aderesh
13

Da keine der oben genannten Antworten für mich funktioniert hat und die akzeptierte Antwort nur für einen Tastaturfokus funktioniert, bin ich zu folgendem Ansatz gekommen:

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

Tötet sowohl den logischen als auch den Tastaturfokus.

Zyklon
quelle
9

Sie können den Fokus auf einen fokussierbaren Vorfahren setzen. Dieser Code funktioniert auch dann, wenn sich das Textfeld in einer Vorlage ohne fokussierbare Vorfahren in derselben Vorlage befindet:

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
quelle
6

AFAIK, es ist nicht möglich, den Fokus vollständig zu entfernen. Etwas in Ihrem Fenster wird immer den Fokus haben.

Bitbonk
quelle
2

In der Windows Phone-Entwicklung habe ich es gerade getan Focus()oder this.Focus()in der PhoneApplicationPage, und es hat wie ein Zauber funktioniert.

Bruno Lemos
quelle
1

Für mich ist es ziemlich schwierig, besonders wenn ich es mit LostFocus-Bindung verwende. Meine Problemumgehung besteht jedoch darin, ein leeres Etikett hinzuzufügen und sich darauf zu konzentrieren.

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

...

OnKeyDown(object sender, RoutedEventArgs e)
{
  //if is Esc
  ResetFocusArea.Focus();
}
Brian Ng
quelle
0

Meine Antwort spricht die obige Frage nicht direkt an, aber ich habe das Gefühl, dass der Wortlaut dazu geführt hat, dass sie zu "Die Frage" über das programmgesteuerte Entfernen des Fokus wurde. Ein häufiges Szenario, in dem dies erforderlich ist, besteht darin, dass der Benutzer den Fokus löschen kann, wenn er mit der linken Maustaste auf den Hintergrund eines Root-Steuerelements wie eines Fensters klickt.

Um dies zu erreichen, können Sie ein angefügtes Verhalten erstellen, das den Fokus auf ein dynamisch erstelltes Steuerelement (in meinem Fall ein leeres Etikett) umschaltet. Es ist vorzuziehen, dieses Verhalten für Elemente der höchsten Ebene wie Fenster zu verwenden, da es die untergeordneten Elemente durchläuft, um ein Bedienfeld zu finden, dem eine Dummy-Beschriftung hinzugefügt werden kann.

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
quelle