Wie wähle ich automatisch den gesamten fokussierten Text in WPF TextBox aus?

232

Wenn ich SelectAllvon einem GotFocusEreignishandler aus anrufe, funktioniert dies nicht mit der Maus - die Auswahl verschwindet, sobald die Maus losgelassen wird.

EDIT: Die Leute mögen Donnelles Antwort, ich werde versuchen zu erklären, warum es mir nicht so gut gefallen hat wie die akzeptierte Antwort.

  • Es ist komplexer, während die akzeptierte Antwort auf einfachere Weise dasselbe tut.
  • Die Verwendbarkeit der akzeptierten Antwort ist besser. Wenn Sie in die Mitte des Textes klicken, wird der Text beim Loslassen der Maus abgewählt, sodass Sie sofort mit der Bearbeitung beginnen können. Wenn Sie dennoch alle auswählen möchten, drücken Sie einfach die Taste erneut. Diesmal wird die Auswahl beim Loslassen nicht aufgehoben. Wenn ich nach Donelles Rezept in die Mitte des Textes klicke, muss ich das zweite Mal klicken, um ihn bearbeiten zu können. Wenn ich irgendwo innerhalb des Textes oder außerhalb des Textes klicke, bedeutet dies höchstwahrscheinlich, dass ich mit der Bearbeitung beginnen möchte, anstatt alles zu überschreiben.
Sergey Aldoukhov
quelle
Wenn Sie mehr als eine Form haben, wird ihre Antwort immer weniger komplex als die erste. Die Benutzerfreundlichkeit beider Optionen ist umstritten, da Sie die Funktionsweise beider Optionen ändern können.
Thepaulpage
1
@Sergey: Möglicherweise möchten Sie die akzeptierte Antwort auf diese Frage ändern, da es seitdem bessere Antworten gibt. Ich werde meine nicht vorschlagen, aber du könntest;)
Grokys
Frage hat Silverlight-Tag, aber Silverlight hat überhaupt nicht die meisten Ereignisse / Vorschau-Ereignisse. Welche Lösung sollte dann für Silverlight verwendet werden?
Valentin Kuzub
Link "Warum ist der Fokus in WPF so schwierig?" ist kaputt
Maxence
1
Wie in einem Kommentar auf stackoverflow.com/a/2553297/492 unten erwähnt, ist madprops.org/blog/wpf-textbox-selectall-on-focus eine einfache Lösung und behält das ursprüngliche Verhalten der Nouse bei. Ich habe die Ereignisregistrierung in den Konstruktor eingefügt, da ich nur ein WPF-Steuerelement in der App habe.
CAD Kerl

Antworten:

75

Ich weiß nicht, warum die Auswahl im GotFocusEreignis verloren geht.

Eine Lösung besteht jedoch darin, die Auswahl für die GotKeyboardFocusund die GotMouseCaptureEreignisse vorzunehmen. Auf diese Weise wird es immer funktionieren.

gcores
quelle
10
Nee. Wenn Sie mit der Maus in die Mitte des vorhandenen Textes klicken, geht die Auswahl verloren, sobald die Maustaste losgelassen wird.
Sergey Aldoukhov
3
Obwohl - nach einem zweiten Klick wird der gesamte Text erneut ausgewählt ... Ich bin mir nicht sicher, ob es sich um ein beabsichtigtes Verhalten von WPF-Designern handelt, aber die Benutzerfreundlichkeit ist nicht so schlecht. Ein weiterer Unterschied zu einem einzelnen GotFocus-Handler besteht darin, dass durch Klicken auf eine leere Stelle in der TextBox alle ausgewählt werden.
Sergey Aldoukhov
3
Dies war auch meine erste Lösung. Aber ich fand, dass Benutzer wirklich verärgert sind, wenn sie nicht in der Lage sind, Text mit der Maus auszuwählen, weil jedes Mal, wenn sie klicken, der gesamte Text ausgewählt wird ...
Nils
1
Ein weiterer Nachteil dieser Lösung besteht darin, dass bei Verwendung des Menüs "Ausschneiden / Kopieren / Einfügen" der TextBox der gesamte Text ausgewählt wird, wenn Sie einen Menüpunkt auswählen.
@gcores Ich weiß, dass dies alt ist, aber weiß jemand, warum im GotFocus-Ereignis der ausgewählte Text verloren geht? Sie haben Recht damit, dass Sie bei anderen Veranstaltungen arbeiten, und das ist in meinem Buch eine durchaus akzeptable Lösung.
Täuschen Sie den
210

Wir haben es so, dass der erste Klick alle auswählt und ein weiterer Klick zum Cursor geht (unsere Anwendung ist für die Verwendung auf Tablets mit Stiften konzipiert).

Vielleicht finden Sie es nützlich.

public class ClickSelectTextBox : TextBox
{
    public ClickSelectTextBox()
    {
        AddHandler(PreviewMouseLeftButtonDownEvent, 
          new MouseButtonEventHandler(SelectivelyIgnoreMouseButton), true);
        AddHandler(GotKeyboardFocusEvent, 
          new RoutedEventHandler(SelectAllText), true);
        AddHandler(MouseDoubleClickEvent, 
          new RoutedEventHandler(SelectAllText), true);
    }

    private static void SelectivelyIgnoreMouseButton(object sender, 
                                                     MouseButtonEventArgs e)
    {
        // Find the TextBox
        DependencyObject parent = e.OriginalSource as UIElement;
        while (parent != null && !(parent is TextBox))
            parent = VisualTreeHelper.GetParent(parent);

        if (parent != null)
        {
            var textBox = (TextBox)parent;
            if (!textBox.IsKeyboardFocusWithin)
            {
                // If the text box is not yet focussed, give it the focus and
                // stop further processing of this click event.
                textBox.Focus();
                e.Handled = true;
            }
        }
    }

    private static void SelectAllText(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox != null)
            textBox.SelectAll();
    }
}
Donnelle
quelle
9
Vielen Dank dafür. Dies funktioniert wunderbar und sollte meiner Meinung nach die akzeptierte Antwort sein. Der obige Code funktioniert, wenn die TextBox den Fokus entweder über die Tastatur oder die Maus (und anscheinend über den Stift) erhält. +1
Drew Noakes
5
Ich habe hier eine fast identische Antwort gesehen . Gibt es einen Vorteil bei all dem?
Marco Luglio
1
Funktioniert hervorragend, wäre aber perfekt, wenn es weiterhin möglich wäre, Text mit der Maus per Drag & Drop auszuwählen. Die Adressleiste von Google Chrome ist ein perfektes Beispiel für das ideale System: Wenn der Nutzer ohne Ziehen klickt und loslässt, wird der gesamte Text hervorgehoben. Wenn der Benutzer jedoch klickt und zieht, wählt das Ziehen Text normal aus, ohne alle auszuwählen. Der SelectAll tritt nur auf Maus - Release . Ich werde herumspielen und sehen, ob ich dieses Design überhaupt verbessern kann.
Devios1
2
Ein weiterer Nachteil dieser Lösung besteht darin, dass bei Verwendung des Menüs "Ausschneiden / Kopieren / Einfügen" der TextBox der gesamte Text ausgewählt wird, wenn Sie einen Menüpunkt auswählen.
1
Ich fand, dass ein zusätzlicher Test in der SelectAllTextMethode es textBox.IsFocusedverbessert. Sie möchten nicht alle auswählen, wenn dies GetKeyboardFocusauf Alt-Tabs im Programm zurückzuführen ist.
Scott Stafford
164

Donnelles Antwort funktioniert am besten, aber eine neue Klasse ableiten zu müssen, um sie zu verwenden, ist ein Schmerz.

Stattdessen registriere ich Handler, die Handler in App.xaml.cs für alle TextBoxen in der Anwendung. Dadurch kann ich die Antwort eines Donnelle mit dem Standard-TextBox-Steuerelement verwenden.

Fügen Sie Ihrer App.xaml.cs die folgenden Methoden hinzu:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e) 
    {
        // Select the text in a TextBox when it receives focus.
        EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseLeftButtonDownEvent,
            new MouseButtonEventHandler(SelectivelyIgnoreMouseButton));
        EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotKeyboardFocusEvent, 
            new RoutedEventHandler(SelectAllText));
        EventManager.RegisterClassHandler(typeof(TextBox), TextBox.MouseDoubleClickEvent,
            new RoutedEventHandler(SelectAllText));
        base.OnStartup(e); 
    }

    void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
    {
        // Find the TextBox
        DependencyObject parent = e.OriginalSource as UIElement;
        while (parent != null && !(parent is TextBox))
            parent = VisualTreeHelper.GetParent(parent);

        if (parent != null)
        {
            var textBox = (TextBox)parent;
            if (!textBox.IsKeyboardFocusWithin)
            {
                // If the text box is not yet focused, give it the focus and
                // stop further processing of this click event.
                textBox.Focus();
                e.Handled = true;
            }
        }
    }

    void SelectAllText(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox != null)
            textBox.SelectAll();
    }
}
Grokys
quelle
4
Dies ist eine ziemlich coole Lösung, die auch von Matt Hamilton vor langer
Ashley Davis
Ich habe einige Rechtschreibfehler in "erhält", "konzentriert"
Nate Zaugg
2
Danke Nate, korrigiert, obwohl ich zu meiner Verteidigung darauf hinweisen möchte, dass die Rechtschreibfehler wörtlich aus Donnelles Antwort kopiert wurden;)
Grokys
Frage hat Silverlight-Tag, aber Silverlight hat überhaupt nicht die meisten Ereignisse / Vorschau-Ereignisse. Welche Lösung sollte dann für Silverlight verwendet werden?
Vielen
4
"Die fokussierte Rechtschreibung ist in den USA viel häufiger. Die fokussierte Rechtschreibung wird jedoch manchmal in Großbritannien und Kanada verwendet und ist besonders in Australien und Neuseeland verbreitet." Also nyah;)
Donnelle
85

Das ist ziemlich alt, aber ich werde trotzdem meine Antwort anzeigen.

Ich habe einen Teil von Donnelles Antwort ausgewählt (den Doppelklick übersprungen), weil ich dies für natürlicher halte. Wie bei gcores mag ich es jedoch nicht, eine abgeleitete Klasse zu erstellen. Aber ich mag auch keine Gcores- OnStartupMethode. Und das brauche ich "allgemein aber nicht immer".

Ich habe dies als Anhang implementiert, DependencyPropertydamit ich es local:SelectTextOnFocus.Active = "True"in xaml einstellen kann. Ich finde diesen Weg am angenehmsten.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

public class SelectTextOnFocus : DependencyObject
{
    public static readonly DependencyProperty ActiveProperty = DependencyProperty.RegisterAttached(
        "Active",
        typeof(bool),
        typeof(SelectTextOnFocus),
        new PropertyMetadata(false, ActivePropertyChanged));

    private static void ActivePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is TextBox)
        {
            TextBox textBox = d as TextBox;
            if ((e.NewValue as bool?).GetValueOrDefault(false))
            {
                textBox.GotKeyboardFocus += OnKeyboardFocusSelectText;
                textBox.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
            }
            else
            {
                textBox.GotKeyboardFocus -= OnKeyboardFocusSelectText;
                textBox.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDown;
            }
        }
    }

    private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        DependencyObject dependencyObject = GetParentFromVisualTree(e.OriginalSource);

        if (dependencyObject == null)
        {
            return;
        }

        var textBox = (TextBox)dependencyObject;
        if (!textBox.IsKeyboardFocusWithin)
        {
            textBox.Focus();
            e.Handled = true;
        }
    }

    private static DependencyObject GetParentFromVisualTree(object source)
    {
        DependencyObject parent = source as UIElement;
        while (parent != null && !(parent is TextBox))
        {
            parent = VisualTreeHelper.GetParent(parent);
        }

        return parent;
    }

    private static void OnKeyboardFocusSelectText(object sender, KeyboardFocusChangedEventArgs e)
    {
        TextBox textBox = e.OriginalSource as TextBox;
        if (textBox != null)
        {
            textBox.SelectAll();
        }
    }

    [AttachedPropertyBrowsableForChildrenAttribute(IncludeDescendants = false)]
    [AttachedPropertyBrowsableForType(typeof(TextBox))]
    public static bool GetActive(DependencyObject @object)
    {
        return (bool) @object.GetValue(ActiveProperty);
    }

    public static void SetActive(DependencyObject @object, bool value)
    {
        @object.SetValue(ActiveProperty, value);
    }
}

Für meine Funktion "Allgemein, aber nicht immer" habe ich diese Attache-Eigenschaft Truein a (global) festgelegt TextBox Style. Auf diese Weise ist "Auswählen des Textes" immer "Ein", aber ich kann ihn pro Textfeld deaktivieren.

Nils
quelle
8
+1 Dies ist viel besser als das globale Festlegen, und es ist eher der WPF-Weg als das Ableiten von TextBox.
Stijn
3
+1 Stimme mit stijn überein. Das "Verstecken" Ihres Codes in der app.cs ist nicht gut für den armen Entwickler, der herausfinden muss, warum SelectAllOnFocus stattfindet. :-) Ich habe dies gerade in meine Klasse für TextBoxBehaviors aufgenommen und dann meinen Basis-TextBox-Stil aktualisiert. Arbeitete eine Belohnung. Prost
Lee Campbell
2
@tronda: Fügen Sie den Ressourcen einfach einen Stil hinzu, indem Sie einen TargetType von TextBox verwenden. Ich schlage vor, Sie werfen einen Blick auf wpftutorial.net/Styles.html
Nils
2
Noch eine +1 für die beste Antwort. Das einzige Problem, das ich finde, ist, dass der Text immer ausgewählt wird, auch wenn ich die rechte Maustaste verwende - was ich häufig mache, um den Text über das Kontextmenü zu bearbeiten -. Die Lösung funktioniert in diesem Fall nicht, da immer der gesamte Text ausgewählt wird, auch wenn ich Ich wollte nur 1 Wort über das Kontextmenü schneiden. Weißt du, wie man das behebt?
user3313608
2
Ich mag diese Antwort, aber warum müssen Sie DependencyObject erweitern? Ich habe das entfernt und es funktioniert immer noch gut.
Fred
47

Hier sind die Verhaltensweisen von Blend, die die Antwortlösung für Ihre Bequemlichkeit implementieren:

Eine zum Anhängen an eine einzelne TextBox:

public class SelectAllTextOnFocusBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.GotKeyboardFocus += AssociatedObjectGotKeyboardFocus;
        AssociatedObject.GotMouseCapture += AssociatedObjectGotMouseCapture;
        AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectPreviewMouseLeftButtonDown;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.GotKeyboardFocus -= AssociatedObjectGotKeyboardFocus;
        AssociatedObject.GotMouseCapture -= AssociatedObjectGotMouseCapture;
        AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectPreviewMouseLeftButtonDown;
    }

    private void AssociatedObjectGotKeyboardFocus(object sender,
        System.Windows.Input.KeyboardFocusChangedEventArgs e)
    {
        AssociatedObject.SelectAll();
    }

    private void AssociatedObjectGotMouseCapture(object sender,
        System.Windows.Input.MouseEventArgs e)
    {
        AssociatedObject.SelectAll();   
    }

    private void AssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if(!AssociatedObject.IsKeyboardFocusWithin)
        {
            AssociatedObject.Focus();
            e.Handled = true;
        }
    }
}

Und eine zum Anhängen an das Stammverzeichnis eines Containers mit mehreren TextBoxen:

public class SelectAllTextOnFocusMultiBehavior : Behavior<UIElement>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.GotKeyboardFocus += HandleKeyboardFocus;
        AssociatedObject.GotMouseCapture += HandleMouseCapture;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.GotKeyboardFocus -= HandleKeyboardFocus;
        AssociatedObject.GotMouseCapture -= HandleMouseCapture;
    }

    private static void HandleKeyboardFocus(object sender,
        System.Windows.Input.KeyboardFocusChangedEventArgs e)
    {
        var txt = e.NewFocus as TextBox;
        if (txt != null)
            txt.SelectAll();
    }

    private static void HandleMouseCapture(object sender,
        System.Windows.Input.MouseEventArgs e)
    {
        var txt = e.OriginalSource as TextBox;
        if (txt != null)
            txt.SelectAll();
    }
}
Sergey Aldoukhov
quelle
Dies ist bei weitem die beste und sauberste Lösung. Vielen Dank für das Teilen.
Golvellius
Es sieht wirklich gut aus, aber aus irgendeinem Grund bricht es die Tab-Kontrolle ... Irgendeine Idee warum?
Marc
Ich möchte Ihre Lösung verwenden. Aber wirklich verloren ... haben Sie vielleicht eine Probe?
Juan Pablo Gomez
Wenn Sie im Fokus auf eine Stelle im Textfeld klicken (stellen Sie sich vor, Sie möchten Caret an einen anderen Ort verschieben), wird SelectAll erneut ausgewählt, anstatt Caret zu verschieben. Es ist unerwartet. Es wurde behoben, indem GotMouseCapture durch MouseDoubleClick ersetzt wurde, was häufig vorkommt. Dank letzterer Lösungen von MSDN.
Norekhov
1
Es scheint nicht zu funktionieren, wenn das Textfeld über FocusManager.FocusedElement den ersten Fokus erhält. Irgendwelche Ideen warum?
Szx
24

Obwohl dies eine alte Frage ist, hatte ich dieses Problem gerade, löste es jedoch mit einem angehängten Verhalten und nicht mit einem Ausdrucksverhalten wie in Sergeys Antwort. Dies bedeutet, dass ich System.Windows.Interactivityim Blend SDK keine Abhängigkeit von Folgendes benötige :

public class TextBoxBehavior
{
    public static bool GetSelectAllTextOnFocus(TextBox textBox)
    {
        return (bool)textBox.GetValue(SelectAllTextOnFocusProperty);
    }

    public static void SetSelectAllTextOnFocus(TextBox textBox, bool value)
    {
        textBox.SetValue(SelectAllTextOnFocusProperty, value);
    }

    public static readonly DependencyProperty SelectAllTextOnFocusProperty =
        DependencyProperty.RegisterAttached(
            "SelectAllTextOnFocus",
            typeof (bool),
            typeof (TextBoxBehavior),
            new UIPropertyMetadata(false, OnSelectAllTextOnFocusChanged));

    private static void OnSelectAllTextOnFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBox = d as TextBox;
        if (textBox == null) return;

        if (e.NewValue is bool == false) return;

        if ((bool) e.NewValue)
        {
            textBox.GotFocus += SelectAll;
            textBox.PreviewMouseDown += IgnoreMouseButton;
        }
        else
        {
            textBox.GotFocus -= SelectAll;
            textBox.PreviewMouseDown -= IgnoreMouseButton;
        }
    }

    private static void SelectAll(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox == null) return;
        textBox.SelectAll();
    }

    private static void IgnoreMouseButton(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        var textBox = sender as TextBox;
        if (textBox == null || (!textBox.IsReadOnly && textBox.IsKeyboardFocusWithin)) return;

        e.Handled = true;
        textBox.Focus();
    }
}

Sie können es dann wie folgt in Ihrer XAML verwenden:

<TextBox Text="Some Text" behaviors:TextBoxBehavior.SelectAllTextOnFocus="True"/>

Ich darüber gebloggt hier .

Dutts
quelle
Ich mag diesen Ansatz, aber die Get / Set-Methoden sollten nicht mit "Property" enden. Ich musste das entfernen, damit der Code nach dem Hinzufügen des Xaml-Teils kompiliert wurde.
Patrick Quirk
Sehr schön, hat wie erwartet funktioniert. Ich mag das, weil es mir hilft, View-Bedenken bei MVVM getrennt zu halten.
Killnine
16

Hier ist eine sehr gute, sehr einfache Lösung für MSDN :

<TextBox
    MouseDoubleClick="SelectAddress"
    GotKeyboardFocus="SelectAddress"
    PreviewMouseLeftButtonDown="SelectivelyIgnoreMouseButton" />

Hier ist der Code dahinter:

private void SelectAddress(object sender, RoutedEventArgs e)
{
    TextBox tb = (sender as TextBox);
    if (tb != null)
    {
        tb.SelectAll();
    }
}

private void SelectivelyIgnoreMouseButton(object sender,
    MouseButtonEventArgs e)
{
    TextBox tb = (sender as TextBox);
    if (tb != null)
    {
        if (!tb.IsKeyboardFocusWithin)
        {
            e.Handled = true;
            tb.Focus();
        }
    }
}
BillBR
quelle
1
Im Wesentlichen ist dies die gleiche Lösung wie die am besten bewertete in diesem Thread. Aber seit zwei Jahren weiß ich jetzt, woher @Donnelle es ausgeliehen hat;)
Sergey Aldoukhov
Diese Lösung schien die einfachste zu sein und funktionierte für mich. Ich wollte eine bestimmte Teilmenge von Text, die standardmäßig beim Eingeben des Textfelds ausgewählt wurde.
Jack B Nimble
10

Ich denke das funktioniert gut:

private void ValueText_GotFocus(object sender, RoutedEventArgs e)
{
    TextBox tb = (TextBox)e.OriginalSource;
    tb.Dispatcher.BeginInvoke(
        new Action(delegate
            {
                tb.SelectAll();
            }), System.Windows.Threading.DispatcherPriority.Input);
}

Wenn Sie es als Erweiterungsmethode implementieren möchten:

public static void SelectAllText(this System.Windows.Controls.TextBox tb)
{
    tb.Dispatcher.BeginInvoke(
        new Action(delegate
        {
            tb.SelectAll();
        }), System.Windows.Threading.DispatcherPriority.Input);
}

Und in Ihrer GotFocusVeranstaltung:

private void ValueText_GotFocus(object sender, RoutedEventArgs e)
{
    TextBox tb = (TextBox)e.OriginalSource;
    tb.SelectAllText();
}

Ich habe die obige Lösung entdeckt, weil ich vor einigen Monaten nach einer Möglichkeit gesucht habe, den Fokus auf eine bestimmte zu legen UIElement. Ich habe den folgenden Code irgendwo entdeckt (hiermit wird eine Gutschrift erteilt) und er funktioniert gut. Ich poste es, obwohl es nicht direkt mit der Frage des OP zusammenhängt, weil es das gleiche Muster für die DispatcherArbeit mit a zeigt UIElement.

// Sets focus to uiElement
public static void DelayedFocus(this UIElement uiElement)
{
    uiElement.Dispatcher.BeginInvoke(
    new Action(delegate
    {
        uiElement.Focusable = true;
        uiElement.Focus();
        Keyboard.Focus(uiElement);
    }),
    DispatcherPriority.Render);
}
Sam
quelle
Ich denke, dies ist die einfachste Methode zur Implementierung. Nach dem Erstellen der Erweiterungsmethode müssen Sie nur noch myTextBox.SelectAllText () aufrufen. Warum erhält diese Antwort nicht mehr Punkte? Warum sind die anderen Lösungen so viel besser?
Tono Nam
2
Ich würde diese Methode vermeiden, da sie auf einem asynchronen Aufruf basiert, der nach dem MouseUp-Handler der Textbox ausgeführt wird. Ich würde nicht darauf vertrauen, dass dies zu 100% deterministisch ist und zu inkonsistentem Verhalten führen kann. Auch wenn es unwahrscheinlich ist, dass es auftritt, würde ich lieber die oben genannten todsicheren Methoden anwenden.
Rob H
6

Hier ist ein Versuch, einige der Probleme mit anderen Lösungen zu lösen:

  1. Wenn Sie das Kontextmenü mit der rechten Maustaste für Ausschneiden / Kopieren / Einfügen verwenden, wird der gesamte Text ausgewählt, auch wenn Sie nicht alles ausgewählt haben.
  2. Bei der Rückkehr aus dem Kontextmenü mit der rechten Maustaste wird immer der gesamte Text ausgewählt.
  3. Wenn Sie mit Alt+ zur Anwendung zurückkehren, Tabwird immer der gesamte Text ausgewählt.
  4. Wenn Sie versuchen, beim ersten Klick nur einen Teil des Texts auszuwählen, wird immer alles ausgewählt (im Gegensatz zur Adressleiste von Google Chromes zum Beispiel).

Der Code, den ich geschrieben habe, ist konfigurierbar. Sie können wählen , welche Aktionen das ganze Verhalten auswählen , indem Sie drei Nur - Lese - Felder auftreten sollte: SelectOnKeybourdFocus, SelectOnMouseLeftClick, SelectOnMouseRightClick.

Der Nachteil dieser Lösung ist, dass sie komplexer ist und der statische Zustand gespeichert wird. Es scheint ein hässlicher Kampf mit dem Standardverhalten der TextBoxKontrolle zu sein. Trotzdem funktioniert es und der gesamte Code ist in der Containerklasse Attached Property versteckt.

public static class TextBoxExtensions
{
    // Configuration fields to choose on what actions the select all behavior should occur.
    static readonly bool SelectOnKeybourdFocus = true;
    static readonly bool SelectOnMouseLeftClick = true;
    static readonly bool SelectOnMouseRightClick = true;

    // Remembers a right click context menu that is opened 
    static ContextMenu ContextMenu = null;

    // Remembers if the first action on the TextBox is mouse down 
    static bool FirstActionIsMouseDown = false;

    public static readonly DependencyProperty SelectOnFocusProperty =
        DependencyProperty.RegisterAttached("SelectOnFocus", typeof(bool), typeof(TextBoxExtensions), new PropertyMetadata(false, new PropertyChangedCallback(OnSelectOnFocusChanged)));

    [AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
    [AttachedPropertyBrowsableForType(typeof(TextBox))]
    public static bool GetSelectOnFocus(DependencyObject obj)
    {
        return (bool)obj.GetValue(SelectOnFocusProperty);
    }

    public static void SetSelectOnFocus(DependencyObject obj, bool value)
    {
        obj.SetValue(SelectOnFocusProperty, value);
    }

    private static void OnSelectOnFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is TextBox textBox)) return;

        if (GetSelectOnFocus(textBox))
        {
            // Register events
            textBox.PreviewMouseDown += TextBox_PreviewMouseDown;
            textBox.PreviewMouseUp += TextBox_PreviewMouseUp;
            textBox.GotKeyboardFocus += TextBox_GotKeyboardFocus;
            textBox.LostKeyboardFocus += TextBox_LostKeyboardFocus;
        }
        else
        {
            // Unregister events
            textBox.PreviewMouseDown -= TextBox_PreviewMouseDown;
            textBox.PreviewMouseUp -= TextBox_PreviewMouseUp;
            textBox.GotKeyboardFocus -= TextBox_GotKeyboardFocus;
            textBox.LostKeyboardFocus -= TextBox_LostKeyboardFocus;
        }
    }

    private static void TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        if (!(sender is TextBox textBox)) return;

        // If mouse clicked and focus was not in text box, remember this is the first click.
        // This will enable to prevent select all when the text box gets the keyboard focus 
        // right after the mouse down event.
        if (!textBox.IsKeyboardFocusWithin)
        {
            FirstActionIsMouseDown = true;
        }
    }

    private static void TextBox_PreviewMouseUp(object sender, MouseButtonEventArgs e)
    {
        if (!(sender is TextBox textBox)) return;

        // Select all only if:
        // 1) SelectOnMouseLeftClick/SelectOnMouseRightClick is true and left/right button was clicked
        // 3) This is the first click
        // 4) No text is selected
        if (((SelectOnMouseLeftClick && e.ChangedButton == MouseButton.Left) || 
            (SelectOnMouseRightClick && e.ChangedButton == MouseButton.Right)) &&
            FirstActionIsMouseDown &&
            string.IsNullOrEmpty(textBox.SelectedText))
        {
            textBox.SelectAll();
        }

        // It is not the first click 
        FirstActionIsMouseDown = false;
    }

    private static void TextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        if (!(sender is TextBox textBox)) return;

        // Select all only if:
        // 1) SelectOnKeybourdFocus is true
        // 2) Focus was not previously out of the application (e.OldFocus != null)
        // 3) The mouse was pressed down for the first after on the text box
        // 4) Focus was not previously in the context menu
        if (SelectOnKeybourdFocus &&
            e.OldFocus != null &&
            !FirstActionIsMouseDown &&
            !IsObjectInObjectTree(e.OldFocus as DependencyObject, ContextMenu))
        {
            textBox.SelectAll();
        }

        // Forget ContextMenu
        ContextMenu = null;
    }

    private static void TextBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        if (!(sender is TextBox textBox)) return;

        // Remember ContextMenu (if opened)
        ContextMenu = e.NewFocus as ContextMenu;

        // Forget selection when focus is lost if:
        // 1) Focus is still in the application
        // 2) The context menu was not opened
        if (e.NewFocus != null
            && ContextMenu == null)
        {
            textBox.SelectionLength = 0;
        }
    }

    // Helper function to look if a DependencyObject is contained in the visual tree of another object
    private static bool IsObjectInObjectTree(DependencyObject searchInObject, DependencyObject compireToObject)
    {
        while (searchInObject != null && searchInObject != compireToObject)
        {
            searchInObject = VisualTreeHelper.GetParent(searchInObject);
        }

        return searchInObject != null;
    }
}

Um die angehängte Eigenschaft an a TextBoxanzuhängen, müssen Sie lediglich den XML-Namespace ( xmlns) der angehängten Eigenschaft hinzufügen und dann wie folgt verwenden:

<TextBox attachedprop:TextBoxExtensions.SelectOnFocus="True"/>

Einige Hinweise zu dieser Lösung:

  1. Um das Standardverhalten eines Mouse-Down-Ereignisses zu überschreiben und die Auswahl nur eines Teils des Texts beim ersten Klick zu aktivieren, wird der gesamte Text beim Mouse-Up-Ereignis ausgewählt.
  2. Ich musste mich damit auseinandersetzen, dass sich das das TextBoxan seine Auswahl erinnert, nachdem es den Fokus verloren hat. Ich habe dieses Verhalten tatsächlich überschrieben.
  3. Ich musste mich daran erinnern, ob eine Maustaste die erste Aktion auf dem TextBox( FirstActionIsMouseDownstatischen Feld) ist.
  4. Ich musste mich an das Kontextmenü erinnern, das mit einem Rechtsklick geöffnet wurde ( ContextMenustatisches Feld).

Der einzige Nebeneffekt, den ich gefunden habe, ist, wann er SelectOnMouseRightClickwahr ist. Manchmal flackert das Kontextmenü mit der rechten Maustaste, wenn es geöffnet wird, und wenn Sie mit der rechten Maustaste auf ein Leerzeichen klicken, TextBoxwird nicht "Alle auswählen" angezeigt.

Eliahu Aaron
quelle
5

Ich habe festgestellt, dass keine der hier dargestellten Antworten ein Standard-Windows-Textfeld imitiert. Versuchen Sie beispielsweise, in den Leerraum zwischen dem letzten Zeichen des Textfelds und der rechten Seite des Textfelds zu klicken. Die meisten Lösungen hier wählen immer den gesamten Inhalt aus, was es sehr schwierig macht, Text an ein Textfeld anzuhängen.

Die Antwort, die ich hier präsentiere, verhält sich in dieser Hinsicht besser. Es handelt sich um ein Verhalten (daher ist die Assembly System.Windows.Interactivity aus dem Blend SDK erforderlich ). Es kann auch mit angehängten Eigenschaften neu geschrieben werden.

public sealed class SelectAllTextOnFocusBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObject_PreviewMouseLeftButtonDown;
    }

    void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        // Find the textbox
        DependencyObject parent = e.OriginalSource as UIElement;
        while (parent != null && !(parent is TextBox))
            parent = VisualTreeHelper.GetParent(parent);

        var textBox = parent as TextBox;
        Debug.Assert(textBox != null);

        if (textBox.IsFocused) return;

        textBox.SelectAll();
        Keyboard.Focus(textBox);
        e.Handled = true;
    }
}

Dies basiert auf Code, den ich hier gefunden habe .

Kristof Verbiest
quelle
1
Dies ist zwar eine gute Antwort, aber ich denke, wenn der Benutzer auf den Leerraum klickt, besteht seine Absicht (in einer Geschäftsanwendung) höchstwahrscheinlich darin, den gesamten Wert zu überschreiben. Daher ist die Auswahl aller der richtige Ansatz.
Sergey Aldoukhov
1
Sergey: Mit dem ersten Klick wird der gesamte Wert ausgewählt, mit dem zweiten Klick wird der Cursor rechts neben den Wert gesetzt. Bei den anderen vorgestellten Lösungen behält der zweite Klick den gesamten ausgewählten Wert bei, was es sehr schwierig macht, ihn an den Wert anzuhängen.
Kristof Verbiest
Wie wird das verwendet? Ich habe diesen Code zu App.xaml.cs hinzugefügt, aber er schien keine Auswirkungen auf die Textfelder in meiner App zu haben.
PIntag
5

Diese einfache Implementierung funktioniert perfekt für mich:

void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    ((TextBox) sender).SelectAll();
}

void TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    var TextBox = (TextBox) sender;
    if (!TextBox.IsKeyboardFocusWithin)
    {
        TextBox.Focus();
        e.Handled = true;
    }
}

Um es auf alle anzuwenden, geben Sie TextBoxden folgenden Code einInitializeComponent();

EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotFocusEvent, new RoutedEventHandler(TextBox_GotFocus));
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseDownEvent, new MouseButtonEventHandler(TextBox_PreviewMouseDown));
Danny Beckett
quelle
4

In der App.xaml-Datei:

<Application.Resources>
    <Style TargetType="TextBox">
        <EventSetter Event="GotKeyboardFocus" Handler="TextBox_GotKeyboardFocus"/>
    </Style>
</Application.Resources>

In der Datei App.xaml.cs:

private void TextBox_GotKeyboardFocus(Object sender, KeyboardFocusChangedEventArgs e)
{
    ((TextBox)sender).SelectAll();
}

Mit diesem Code erreichen Sie alle TextBoxin Ihrer Anwendung.

Darshan Faldu
quelle
3

Von hier genommen :

Registrieren Sie den globalen Ereignishandler in der Datei App.xaml.cs:

protected override void OnStartup(StartupEventArgs e)
{
    EventManager.RegisterClassHandler(typeof(TextBox),TextBox.GotFocusEvent,
    new RoutedEventHandler(TextBox_GotFocus));

    base.OnStartup(e);
}

Dann ist der Handler so einfach wie:

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    (sender as TextBox).SelectAll();
}
Neomoon
quelle
3

Mir ist klar, dass dies sehr alt ist, aber hier ist meine Lösung, die auf den Ausdrücken / Microsoft-Interaktivität und den Namensräumen für Interaktionen basiert.

Zuerst habe ich die Anweisungen unter diesem Link befolgt , um Interaktivitätsauslöser in einen Stil einzufügen.

Dann kommt es darauf an

<Style x:Key="baseTextBox" TargetType="TextBox">
  <Setter Property="gint:InteractivityItems.Template">
    <Setter.Value>
      <gint:InteractivityTemplate>
        <gint:InteractivityItems>
          <gint:InteractivityItems.Triggers>
            <i:EventTrigger EventName="GotKeyboardFocus">
              <ei:CallMethodAction MethodName="SelectAll"/>
            </i:EventTrigger>
            <i:EventTrigger EventName="PreviewMouseLeftButtonDown">
              <ei:CallMethodAction MethodName="TextBox_PreviewMouseLeftButtonDown"
                TargetObject="{Binding ElementName=HostElementName}"/>
            </i:EventTrigger>
          </gint:InteractivityItems.Triggers>
        </gint:InteractivityItems>
      </gint:InteractivityTemplate>
    </Setter.Value>
  </Setter>
</Style>

und das

public void TextBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
  TextBox tb = e.Source as TextBox;
  if((tb != null) && (tb.IsKeyboardFocusWithin == false))
  {
    tb.Focus();
    e.Handled = true;
  }
}

In meinem Fall habe ich ein Benutzersteuerelement, bei dem sich die Textfelder mit einem Code-Behind befinden. Der CodeBehind hat die Handlerfunktion. Ich habe meinem Benutzersteuerelement in XAML einen Namen gegeben und verwende diesen Namen für das Element. Das funktioniert perfekt für mich. Wenden Sie den Stil einfach auf eine beliebige Stelle TextBoxan, an der der gesamte Text ausgewählt werden soll, wenn Sie auf klicken TextBox.

Der erste CallMethodActionruft die SelectAllMethode des Textfelds auf , wenn das GotKeyboardFocusEreignis TextBoxausgelöst wird.

Ich hoffe das hilft.

wiyosaya
quelle
Da es sich um so alte Fragen handelt, kann es hilfreich sein, Ihre Antwort zu beachten, wenn Sie erwähnen, warum sich jemand für diesen Ansatz entscheidet.
Divibisan
Zunächst muss dies nicht in einen Stil eingefügt werden, aber ich denke, es ist offensichtlich, dass es viele Textfeld-Steuerelemente gibt, die dies benötigen. Ein Stil ist der richtige Weg.
Wiyosaya
1
Möglicherweise stimmen einige mit diesem Ansatz nicht überein. Es ist jedoch nicht erforderlich, TextBox in Unterklassen zu unterteilen, Klassenhandlerereignisse, Erweiterungsmethoden zu erstellen, angehängte Eigenschaften zu erstellen usw. Als Stil kann er auch hinzugefügt werden zum Ressourcenwörterbuch eines beliebigen xaml-Projekts. Ohne den Schlüssel x: würde er auf jede TextBox-Instanz im Bereich des Ressourcenwörterbuchs angewendet, ohne dass die xaml jedes einzelnen Textfelds geändert werden muss. In einigen Fällen kann es sich um einen saubereren Ansatz handeln.
Wiyosaya
2

Ich habe Nils 'Antwort verwendet, aber auf flexibler umgestellt.

public enum SelectAllMode
{

    /// <summary>
    ///  On first focus, it selects all then leave off textbox and doesn't check again
    /// </summary>
    OnFirstFocusThenLeaveOff = 0,

    /// <summary>
    ///  On first focus, it selects all then never selects
    /// </summary>
    OnFirstFocusThenNever = 1,

    /// <summary>
    /// Selects all on every focus
    /// </summary>
    OnEveryFocus = 2,

    /// <summary>
    /// Never selects text (WPF's default attitude)
    /// </summary>
    Never = 4,
}

public partial class TextBox : DependencyObject
{
    public static readonly DependencyProperty SelectAllModeProperty = DependencyProperty.RegisterAttached(
        "SelectAllMode",
        typeof(SelectAllMode?),
        typeof(TextBox),
        new PropertyMetadata(SelectAllModePropertyChanged));

    private static void SelectAllModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is System.Windows.Controls.TextBox)
        {
            var textBox = d as System.Windows.Controls.TextBox;

            if (e.NewValue != null)
            {
                textBox.GotKeyboardFocus += OnKeyboardFocusSelectText;
                textBox.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
            }
            else
            {
                textBox.GotKeyboardFocus -= OnKeyboardFocusSelectText;
                textBox.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDown;
            }
        }
    }

    private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        DependencyObject dependencyObject = GetParentFromVisualTree(e.OriginalSource);

        if (dependencyObject == null)
            return;

        var textBox = (System.Windows.Controls.TextBox)dependencyObject;
        if (!textBox.IsKeyboardFocusWithin)
        {
            textBox.Focus();
            e.Handled = true;
        }
    }

    private static DependencyObject GetParentFromVisualTree(object source)
    {
        DependencyObject parent = source as UIElement;
        while (parent != null && !(parent is System.Windows.Controls.TextBox))
        {
            parent = VisualTreeHelper.GetParent(parent);
        }

        return parent;
    }

    private static void OnKeyboardFocusSelectText(object sender, KeyboardFocusChangedEventArgs e)
    {
        var textBox = e.OriginalSource as System.Windows.Controls.TextBox;
        if (textBox == null) return;

        var selectAllMode = GetSelectAllMode(textBox);

        if (selectAllMode == SelectAllMode.Never)
        {
            textBox.SelectionStart = 0;
            textBox.SelectionLength = 0;
        }
        else
            textBox.SelectAll();

        if (selectAllMode == SelectAllMode.OnFirstFocusThenNever)
            SetSelectAllMode(textBox, SelectAllMode.Never);
        else if (selectAllMode == SelectAllMode.OnFirstFocusThenLeaveOff)
            SetSelectAllMode(textBox, null);
    }

    [AttachedPropertyBrowsableForChildrenAttribute(IncludeDescendants = false)]
    [AttachedPropertyBrowsableForType(typeof(System.Windows.Controls.TextBox))]
    public static SelectAllMode? GetSelectAllMode(DependencyObject @object)
    {
        return (SelectAllMode)@object.GetValue(SelectAllModeProperty);
    }

    public static void SetSelectAllMode(DependencyObject @object, SelectAllMode? value)
    {
        @object.SetValue(SelectAllModeProperty, value);
    }
}

In XAML können Sie Folgendes verwenden:

<!-- On first focus, it selects all then leave off textbox and doesn't check again -->
<TextBox attprop:TextBox.SelectAllMode="OnFirstFocusThenLeaveOff" />

<!-- On first focus, it selects all then never selects -->
<TextBox attprop:TextBox.SelectAllMode="OnFirstFocusThenNever" />

<!-- Selects all on every focus -->
<TextBox attprop:TextBox.SelectAllMode="OnEveryFocus" />

<!-- Never selects text (WPF's default attitude) -->
<TextBox attprop:TextBox.SelectAllMode="Never" />
bafsar
quelle
1
Wirklich gute Lösung für die Verwendung in Vorlagen, da Sie es an xaml binden können, ohne dass sich ein tatsächlicher Code dahinter befindet, sondern nur das Verhalten des Textfelds erweitert.
Eric Johansson
2

Hier ist die C # -Version der Antwort von @Nasenbaer

private delegate void TextBoxSelectAllDelegate(object sender);

private void TextBoxSelectAll(object sender)
{
    (sender as System.Windows.Controls.TextBox).SelectAll();
}

private void MyTextBox_GotFocus(object sender, System.Windows.RoutedEventArgs e)
{
    TextBoxSelectAllDelegate d = TextBoxSelectAll;

    this.Dispatcher.BeginInvoke(d,
        System.Windows.Threading.DispatcherPriority.ApplicationIdle, sender);
}

wohingegen MyTextBox_GotFocusder Ereignishandler dem GotFocusEreignis von zugeordnet ist MyTextBox.

ViRuSTriNiTy
quelle
2

Ich habe eine leicht vereinfachte Antwort darauf (mit nur dem PreviewMouseLeftButtonDownEreignis), die die übliche Funktionalität eines Browsers zu imitieren scheint:

In XAML haben Sie ein TextBoxMitspracherecht:

<TextBox Text="http://www.blabla.com" BorderThickness="2" BorderBrush="Green" VerticalAlignment="Center" Height="25"
                 PreviewMouseLeftButtonDown="SelectAll" />

Im Codebehind:

private void SelectAll(object sender, MouseButtonEventArgs e)
{
    TextBox tb = (sender as TextBox);

    if (tb == null)
    {
        return;
    }

    if (!tb.IsKeyboardFocusWithin)
    {
        tb.SelectAll();
        e.Handled = true;
        tb.Focus();
    }
}
Danield
quelle
1
Möglicherweise möchten Sie ein GotKeyboardFocus-Ereignis mit TextBox.SelectAll () für Personen hinzufügen, die sich in Ihrer Anwendung bewegen. Ihre Lösung funktioniert auch für PasswordBoxen (da PasswordBoxen versiegelte Typen sind, können sie nicht erweitert werden).
David Sherret
1

Versuchen Sie diese Erweiterungsmethode, um jedem TextBox-Steuerelement das gewünschte Verhalten hinzuzufügen. Ich habe es noch nicht ausgiebig getestet, aber es scheint meine Bedürfnisse zu erfüllen.

public static class TextBoxExtensions
{
    public static void SetupSelectAllOnGotFocus(this TextBox source)
    {
        source.GotFocus += SelectAll;
        source.PreviewMouseLeftButtonDown += SelectivelyIgnoreMouseButton;
    }

    private static void SelectAll(object sender, RoutedEventArgs e)
    {
        var textBox = e.OriginalSource as TextBox;
        if (textBox != null)
            textBox.SelectAll();
    }

    private static void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
    {
        var textBox = (sender as TextBox);
        if (textBox != null)
        {
            if (!textBox.IsKeyboardFocusWithin)
            {
                e.Handled = true;
                textBox.Focus();
            }
        }
    }
}
David Kirkland
quelle
1

Ich habe viel nach der Lösung gesucht und einige Lösungen gefunden, um sie auszuwählen. Das Problem ist jedoch, dass wir, wenn wir mit der rechten Maustaste klicken und nach Auswahl eines Textteils aus dem Textfeld ausschneiden / kopieren, alle auswählen, auch wenn ich einen Textteil ausgewählt habe. Um dies hier zu beheben, ist die Lösung. Fügen Sie einfach den folgenden Code in das Tastaturauswahlereignis ein. Das hat bei mir funktioniert.

private static void SelectContentsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d is TextBox)
    {
        TextBox textBox = d as TextBox;
        if ((e.NewValue as bool?).GetValueOrDefault(false))
        {
            textBox.GotKeyboardFocus += OnKeyboardFocusSelectText;                 
        }
        else
        {
            textBox.GotKeyboardFocus -= OnKeyboardFocusSelectText;

        }
    }
}


private static void OnKeyboardFocusSelectText(object sender, KeyboardFocusChangedEventArgs e)
{
    if (e.KeyboardDevice.IsKeyDown(Key.Tab))
        ((TextBox)sender).SelectAll();
}
Sambu Praveen
quelle
1

Ich hatte das gleiche Problem. In VB.Net funktioniert das ganz einfach:

VB XAML:

<TextBox x:Name="txtFilterFrequency" />

Codehind:

Private Sub txtFilterText_GotFocus(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles txtFilterText.GotFocus
    Me.Dispatcher.BeginInvoke(Sub()
                                  txtFilterText.SelectAll()
                              End Sub, DispatcherPriority.ApplicationIdle, Nothing)
End Sub

C # (danke an ViRuSTriNiTy)

private delegate void TextBoxSelectAllDelegate(object sender);

private void TextBoxSelectAll(object sender)
{
    (sender as System.Windows.Controls.TextBox).SelectAll();
}

private void MyTextBox_GotFocus(object sender, System.Windows.RoutedEventArgs e)
{
    TextBoxSelectAllDelegate d = TextBoxSelectAll;

    this.Dispatcher.BeginInvoke(d,
        System.Windows.Threading.DispatcherPriority.ApplicationIdle, sender);
}
Nasenbaer
quelle
Beste Lösung für mich, ich habe eine C # Übersetzung hier gepostet: stackoverflow.com/a/48385409/3936440
ViRuSTriNiTy
Bei diesem Ansatz wird gelegentlich kein Text ausgewählt. Ich denke, es ist eine Rennbedingung aufgrund von BeginInvoke.
Mumm
Bitte angeben. Die Dispatcher-Priorität arbeitet erwartungsgemäß an Standardanwendungen. Wie ist deine Situation? Haben Sie genau wie beschrieben versucht? Etwas Besonderes an Ihrer Lösung?
Nasenbaer
1

Dies ist bei weitem die einfachste Lösung.

Fügen Sie der Anwendung (App.xaml.cs) einen globalen Handler hinzu und fertig. Sie benötigen nur wenige Codezeilen.

protected override void OnStartup(StartupEventArgs e)
{
    EventManager.RegisterClassHandler(typeof(TextBox),
        TextBox.GotFocusEvent,
        new RoutedEventHandler(TextBox_GotFocus));

    base.OnStartup(e);
}

Verwenden Sie daher die EventManager-Klasse, um einen globalen Ereignishandler für einen Typ (TextBox) zu registrieren. Der eigentliche Handler ist ganz einfach:

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    (sender as TextBox).SelectAll();
}

Überprüfen Sie hier: WPF TextBox SelectAll on Focus

Ich hoffe es hilft.

Marlon Assef
quelle
1

Für diejenigen, die an Donnelles / Grokys Ansatz interessiert sind, aber einen Klick rechts neben dem letzten Zeichen (aber immer noch innerhalb TextBox) wünschen , um das Caret am Ende des eingegebenen Textes zu platzieren, habe ich folgende Lösung gefunden:

int GetRoundedCharacterIndexFromPoint(TextBox textBox, Point clickedPoint)
{
    int position = textBox.GetCharacterIndexFromPoint(clickedPoint, true);

    // Check if the clicked point is actually closer to the next character
    // or if it exceeds the righmost character in the textbox
    // (in this case return increase the position by 1)
    Rect charLeftEdge = textBox.GetRectFromCharacterIndex(position, false);
    Rect charRightEdge = textBox.GetRectFromCharacterIndex(position, true);
    double charWidth = charRightEdge.X - charLeftEdge.X;
    if (clickedPoint.X + charWidth / 2 > charLeftEdge.X + charWidth) position++;

    return position;
}

void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
{
    // Find the TextBox
    DependencyObject parent = e.OriginalSource as UIElement;
    while (parent != null && !(parent is TextBox))
        parent = VisualTreeHelper.GetParent(parent);

    if (parent != null)
    {
        var textBox = (TextBox)parent;
        if (!textBox.IsKeyboardFocusWithin)
        {
            // If the text box is not yet focused, give it the focus and
            // stop further processing of this click event.
            textBox.Focus();
            e.Handled = true;
        }
        else
        {
            int pos = GetRoundedCharacterIndexFromPoint(textBox, e.GetPosition(textBox));
            textBox.CaretIndex = pos;
        }
    }
}

void SelectAllText(object sender, RoutedEventArgs e)
{
    var textBox = e.OriginalSource as TextBox;
    if (textBox != null)
        textBox.SelectAll();
}

Die GetRoundedCharacterIndexFromPointMethode wurde aus diesem Beitrag übernommen.

PIntag
quelle
1
Funktioniert gut, aber das Doppelklick-Ereignis wird nicht ausgelöst
Rodrigo Caballero
Eigentlich wird das Doubleclick-Ereignis eingegeben, aber die OriginalSource-Eigenschaft ist vom Typ TextBoxView. Die SelectAllText-Methode sollte also folgendermaßen aussehen: private static void SelectAllText (Objektabsender, RoutedEventArgs e) {var textBox = e.OriginalSource as TextBox; if (textBox! = null) {textBox.SelectAll (); System.Diagnostics.Debug.WriteLine ("Selected ALL"); } else if (Absender ist TextBox) {(Absender als TextBox) .SelectAll (); }
Rodrigo Caballero
1

Nach dem Googeln und Testen habe ich eine einfache Lösung gefunden, die für mich funktioniert hat.

Sie müssen dem LoadedEreignis Ihres Containerfensters einen Ereignishandler hinzufügen :

private void yourwindow_Loaded(object sender, RoutedEventArgs e)
{
    EventManager.RegisterClassHandler(typeof(TextBox),
        TextBox.PreviewMouseLeftButtonDownEvent,
        new RoutedEventHandler(SelectivelyIgnoreMouseButton));
}

Als Nächstes müssen Sie den Handler für den RoutedEventHandlerim vorherigen Code angegebenen Code erstellen:

private void SelectivelyIgnoreMouseButton(object sender, RoutedEventArgs e)
{
    TextBox tb = (sender as TextBox);
    if (tb != null)
    {
        if (!tb.IsKeyboardFocusWithin)
        {
            e.Handled = true;
            tb.Focus();
        }
    }
}

Jetzt können Sie den SelectAll()Befehl für GotFocusEreignishandler zu allen TextBoxSteuerelementen separat hinzufügen :

private void myTextBox_GotFocus(object sender, RoutedEventArgs e)
{
    (sender as TextBox).SelectAll();
}

Ihr Text wird jetzt im Fokus ausgewählt!

Adaptiert von Dr. WPF-Lösung, MSDN-Foren

DonBeto97
quelle
Ich habe gerade verwendet: private async void TBTime_GotFocus (Objektabsender, RoutedEventArgs e) {TextBox tb = (TextBox) e.OriginalSource; warte auf Dispatcher.RunAsync (Windows.UI.Core.CoreDispatcherPriority.Normal, async () => {tb.SelectAll ();}); }
David Jones
1
#region TextBoxIDCard selection
private bool textBoxIDCardGotFocus = false;
private void TextBoxIDCard_GotFocus(object sender, RoutedEventArgs e)
{
    this.TextBoxIDCard.SelectAll();
}

private void TextBoxIDCard_LostFocus(object sender, RoutedEventArgs e)
{
    textBoxIDCardGotFocus = false;
}

private void TextBoxIDCard_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    if (textBoxIDCardGotFocus == false)
    {
        e.Handled = true;
        this.TextBoxIDCard.Focus();
        textBoxIDCardGotFocus = true;
    }
} 
#endregion
Brian
quelle
Wenn Sie 20 Textfelder in einem Fenster haben, erstellen Sie 3 Methoden für jedes Textfeld? Dieser Ansatz ist nicht gut. Werfen
Alexandru Dicu
0

Das scheint für mich gut zu funktionieren. Es ist im Grunde eine Zusammenfassung einiger früherer Beiträge. Ich habe dies einfach in meine MainWindow.xaml.cs-Datei im Konstruktor eingefügt. Ich erstelle zwei Handler, einen für die Tastatur und einen für die Maus, und führe beide Ereignisse in dieselbe Funktion HandleGotFocusEvent, die direkt nach dem Konstruktor in derselben Datei definiert ist.

public MainWindow()
{
   InitializeComponent();

   EventManager.RegisterClassHandler(typeof(TextBox), 
      UIElement.GotKeyboardFocusEvent,
      new RoutedEventHandler(HandleGotFocusEvent), true);
   EventManager.RegisterClassHandler(typeof(TextBox),
      UIElement.GotMouseCaptureEvent,
      new RoutedEventHandler(HandleGotFocusEvent), true);   
}
private void HandleGotFocusEvent(object sender, RoutedEventArgs e)
{
   if (sender is TextBox)
      (sender as TextBox).SelectAll();
}
Ted
quelle
Schön und einfach, scheint aber ein Timing-Problem zu haben - bei jedem zweiten Versuch (Mausklick) wird die Auswahl sofort wieder aufgehoben ...?
T4NK3R
0

Eine einfache Möglichkeit, den mouseDown zu überschreiben und alle nach einem Doppelklick auszuwählen, ist:

public class DoubleClickTextBox: TextBox
{

    public override void EndInit()
    {
        base.EndInit();            
    }

    protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
    {
        base.OnMouseEnter(e);
        this.Cursor = Cursors.Arrow;
    }
    protected override void OnMouseDown(System.Windows.Input.MouseButtonEventArgs e)
    {

    }

    protected override void OnMouseDoubleClick(System.Windows.Input.MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);
        this.SelectAll();
    }
}
Hessen
quelle
0

Versuchen Sie, dies in den Konstruktor des Steuerelements einzufügen, in dem sich Ihr Textfeld befindet:

Loaded += (sender, e) =>
{
    MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    myTextBox.SelectAll();
}
CodeOtaku
quelle
Dieser Ansatz funktioniert nicht, wenn Sie ihn in einen Fensterkonstruktor einfügen.
ViRuSTriNiTy
0

Wenn es ein Ereignis gibt, bei dem OnFocusdie Auswahl von Text während der Maus aufgehoben wird, verzögere ich normalerweise nur die Auswahl aller.

private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
    if (TextBox.Text != null)
    {
        _ = Task.Run(() =>
        {
            Dispatcher.Invoke(
                async () => {
                    await Task.Delay(100);
                    TextBox.SelectAll();
                }
            );
        });
    }
}
milope
quelle
-1

Ich habe alle getestet, aber nur Folgendes hat funktioniert:

protected override void OnStartup(StartupEventArgs e) 
{
    EventManager.RegisterClassHandler(typeof(TextBox), UIElement.PreviewMouseLeftButtonDownEvent,
   new MouseButtonEventHandler(SelectivelyHandleMouseButton), true);
    EventManager.RegisterClassHandler(typeof(TextBox), UIElement.GotKeyboardFocusEvent,
      new RoutedEventHandler(SelectAllText), true);
    EventManager.RegisterClassHandler(typeof(TextBox), UIElement.GotFocusEvent,
      new RoutedEventHandler(GotFocus), true);          
}

private static void SelectivelyHandleMouseButton(object sender, MouseButtonEventArgs e)
{
    var textbox = (sender as TextBox);
    if (textbox != null)
    {
        int hc = textbox.GetHashCode();
        if (hc == LastHashCode)
        {
            if (e.OriginalSource.GetType().Name == "TextBoxView")
            {
                e.Handled = true;
                textbox.Focus();
                LastHashCode = -1;
            }
        }
    }
    if (textbox != null) textbox.Focus();
}

private static void SelectAllText(object sender, RoutedEventArgs e)
{
    var textBox = e.OriginalSource as TextBox;
    if (textBox != null)
        textBox.SelectAll();
}

private static int LastHashCode;
private static void GotFocus(object sender, RoutedEventArgs e)
{
    var textBox = e.OriginalSource as TextBox;
    if (textBox != null)
        LastHashCode = textBox.GetHashCode();
}
Ehsan Zargar Ershadi
quelle
4
Das ist auch ein obszöner Missbrauch von Hash-Codes. Ich würde dies lesen, Link
RichK
3
Und mit GetType().Nameanstelle von isoder asist ziemlich hacky
RichK
-1

Ich sehe, dass es viele Antworten gibt, aber als genehmigte sollten folgende Methoden angewendet werden EditTextBoxGotCapture

mit folgendem Code dahinter:

private void EditTextBoxGotCapture(object sender, MouseEventArgs e)
{
    if (sender is TextBox tb)
    {
        tb.Select(0, tb.Text.Length);
    }
}
Liviu Sosu
quelle