Comment sélectionner automatiquement tout le texte sur le focus dans WPF TextBox?

232

Si j'appelle à SelectAllpartir d'un GotFocusgestionnaire d'événements, cela ne fonctionne pas avec la souris - la sélection disparaît dès que la souris est relâchée.

EDIT: Les gens aiment la réponse de Donnelle, je vais essayer d'expliquer pourquoi je ne l'aimais pas autant que la réponse acceptée.

  • C'est plus complexe, alors que la réponse acceptée fait la même chose de manière plus simple.
  • La convivialité de la réponse acceptée est meilleure. Lorsque vous cliquez au milieu du texte, le texte n'est pas sélectionné lorsque vous relâchez la souris, ce qui vous permet de commencer à modifier instantanément, et si vous souhaitez toujours tout sélectionner, appuyez à nouveau sur le bouton et cette fois, il ne sera pas désélectionné à la libération. Suivant la recette de Donelle, si je clique au milieu du texte, je dois cliquer une deuxième fois pour pouvoir éditer. Si je clique quelque part dans le texte par rapport à l'extérieur du texte, cela signifie très probablement que je veux commencer à éditer au lieu de tout écraser.
Sergey Aldoukhov
la source
Si vous allez avoir plus d'un formulaire, sa réponse continue de devenir moins complexe que la première. La convivialité des deux options est théorique car vous pouvez modifier le fonctionnement de l'une ou l'autre.
thepaulpage
1
@Sergey: Vous souhaiterez peut-être modifier la réponse acceptée pour cette question, car il y a eu de meilleures réponses depuis. Je ne vais pas suggérer la mienne, mais vous pourriez;)
Grokys
La question a une balise Silverlight, mais Silverlight n'a pas la plupart des événements / aucun type d'événement de prévisualisation. Quelle solution faut-il alors utiliser pour Silverlight?
Valentin Kuzub
Link "Pourquoi le focus dans WPF est-il si délicat?" est cassé
Maxence
1
comme mentionné dans un commentaire sur stackoverflow.com/a/2553297/492 ci-dessous, madprops.org/blog/wpf-textbox-selectall-on-focus est une solution facile et préserve le comportement de nouse d'origine. J'ai mis l'enregistrement d'événement dans le constructeur car je n'ai qu'un seul contrôle WPF dans l'application.
CAD bloke du

Réponses:

75

Je ne sais pas pourquoi il perd la sélection dans l' GotFocusévénement.

Mais une solution est de faire la sélection sur le GotKeyboardFocuset les GotMouseCaptureévénements. De cette façon, cela fonctionnera toujours.

gcores
la source
10
Nan. Lorsque vous cliquez avec la souris au milieu du texte existant - la sélection est perdue dès que le bouton de la souris est relâché.
Sergey Aldoukhov
3
Bien que - après un deuxième clic unique, il sélectionne à nouveau tout le texte ... Je ne sais pas si c'est un comportement prévu des concepteurs WPF, mais la convivialité n'est pas si mauvaise. Une autre différence par rapport à un seul gestionnaire GotFocus est que le fait de cliquer sur un espace vide dans la TextBox sélectionne tout.
Sergey Aldoukhov
3
C'était aussi ma première solution. Mais j'ai trouvé que les utilisateurs sont vraiment ennuyés, lorsqu'ils ne peuvent pas sélectionner le texte à l'aide de la souris, car chaque fois qu'ils cliquent sur tout le texte est sélectionné ...
Nils
1
Un autre inconvénient de cette solution est que lorsque vous utilisez le menu "Couper / Copier / Coller" de TextBox, tout le texte est sélectionné lorsque vous sélectionnez un élément de menu.
@gcores Je sais que c'est ancien, mais quelqu'un sait-il pourquoi dans l'événement GotFocus le texte sélectionné est perdu? Vous avez raison de dire que cela fonctionne dans d'autres événements, et c'est une solution parfaitement acceptable dans mon livre.
Feignez le
210

Nous l'avons donc le premier clic sélectionne tout, et un autre clic va au curseur (notre application est conçue pour être utilisée sur des tablettes avec des stylos).

Vous pourriez trouver cela utile.

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
la source
9
Merci beaucoup pour cela. Cela fonctionne à merveille et devrait être la réponse acceptée à mon humble avis. Le code ci-dessus fonctionne lorsque la TextBox reçoit le focus via le clavier ou la souris (et apparemment le stylet). +1
Drew Noakes
5
J'ai vu une réponse presque identique ici social.msdn.microsoft.com/Forums/en-US/wpf/thread/… , cela fonctionne aussi bien, même s'il n'utilise pas e.OriginalSource, ni ne parcourt l'arborescence visuelle. Y a-t-il un avantage à faire tout cela?
Marco Luglio
1
Fonctionne très bien, mais serait parfait s'il permettait toujours de faire glisser-sélectionner le texte avec la souris. La barre d'adresse de Google Chrome est un exemple parfait du système idéal: si l'utilisateur clique et relâche sans faire glisser, tout le texte est mis en surbrillance. Cependant, si l'utilisateur clique et fait glisser, le glissement sélectionne le texte normalement sans tout sélectionner. Le SelectAll ne se produit qu'à la sortie de la souris . Je vais jouer et voir si je peux améliorer ce design.
devios1
2
Un autre inconvénient de cette solution est que lorsque vous utilisez le menu "Couper / Copier / Coller" de TextBox, tout le texte est sélectionné lorsque vous sélectionnez un élément de menu.
1
J'ai trouvé qu'un test supplémentaire dans la SelectAllTextméthode de l' textBox.IsFocusedaméliorer. Vous ne voulez pas tout sélectionner lorsque le GetKeyboardFocusest dû à une alt-tabulation dans le programme.
Scott Stafford
164

La réponse de Donnelle fonctionne le mieux, mais devoir dériver une nouvelle classe pour l'utiliser est une douleur.

Au lieu de cela, j'enregistre les gestionnaires les gestionnaires dans App.xaml.cs pour tous les TextBox de l'application. Cela me permet d'utiliser la réponse d'un Donnelle avec un contrôle TextBox standard.

Ajoutez les méthodes suivantes à votre App.xaml.cs:

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
la source
4
C'est une solution assez cool, elle a également été décrite par Matt Hamilton il y a longtemps ici: madprops.org/blog/wpf-textbox-selectall-on-focus
Ashley Davis
Vous avez des fautes d'orthographe dans 'reçoit', 'concentré'
Nate Zaugg
2
Merci Nate, corrigé, bien que pour ma défense, je tiens à souligner que les fautes d'orthographe ont été copiées textuellement de la réponse de Donnelle;)
Grokys
La question a une balise Silverlight, mais Silverlight n'a pas la plupart des événements / aucun type d'événement de prévisualisation. Quelle solution faut-il alors utiliser pour Silverlight? merci d'avance
Valentin Kuzub
4
"L'orthographe focalisée est beaucoup plus courante aux États-Unis; cependant, l'orthographe focalisée est parfois utilisée au Royaume-Uni et au Canada, et est particulièrement courante en Australie et en Nouvelle-Zélande." Alors nyah;)
Donnelle
85

C'est assez ancien, mais je vais quand même afficher ma réponse.

J'ai choisi une partie de la réponse Donnelle (sauté le double-clic) car je pense que c'est plus naturel. Cependant, comme gcores, je n'aime pas la nécessité de créer une classe dérivée. Mais je n'aime pas non plus la OnStartupméthode gcores . Et j'en ai besoin sur une base "générale mais pas toujours".

Je l'ai implémenté en tant que pièce jointe DependencyPropertyafin de pouvoir définirlocal:SelectTextOnFocus.Active = "True" pièce en xaml. Je trouve cette façon la plus agréable.

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);
    }
}

Pour ma fonctionnalité "générale mais pas toujours", j'ai défini cette propriété Attache Truedans un (global) TextBox Style. De cette façon, "sélectionner le texte" est toujours "activé", mais je peux le désactiver au cas par cas.

Nils
la source
8
+1, c'est beaucoup mieux que de le définir globalement, et c'est plus «la manière WPF» que de dériver de TextBox.
stijn
3
+1 D'accord avec stijn. «Masquer» votre code dans app.cs n'est pas agréable pour le pauvre développeur qui doit comprendre pourquoi SelectAllOnFocus se produit. :-) Je viens de déposer ceci dans ma classe pour TextBoxBehaviors, puis j'ai mis à jour mon style de base TextBox. Travaillé un régal. Santé
Lee Campbell
2
@tronda: Ajoutez simplement un style aux ressources en utilisant un TargetType de TextBox. Je vous suggère de jeter un œil à wpftutorial.net/Styles.html
Nils
2
Un autre +1 pour la meilleure réponse. Le seul problème que je trouve est que le texte est toujours sélectionné même lorsque j'utilise le bouton droit de la souris - ce que je fais fréquemment pour modifier le texte via le menu contextuel - la solution ne fonctionne pas dans ce cas car il sélectionne toujours tout le texte même si je je voulais juste couper 1 mot via le menu contextuel. Savez-vous comment résoudre ce problème?
user3313608
2
J'aime cette réponse, mais pourquoi devez-vous étendre DependencyObject? J'ai supprimé cela et cela fonctionne toujours bien.
Fred
47

Voici les comportements de mélange implémentant la solution de réponse pour votre commodité:

Un pour attacher à un seul 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;
        }
    }
}

Et un pour attacher à la racine d'un conteneur contenant plusieurs TextBox'es:

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
la source
C'est de loin la solution la meilleure et la plus propre. Merci beaucoup de le partager.
Golvellius
Il a l'air vraiment sympa, mais pour une raison quelconque, il casse le contrôle des onglets ... Une idée pourquoi?
Marc
J'aimerais utiliser votre solution. Mais vraiment perdu ... vous avez peut-être un échantillon?
Juan Pablo Gomez
Lorsque vous cliquez quelque part dans la zone de texte tout en ayant le focus (imaginez que vous voulez déplacer le curseur) vers un autre endroit, il sélectionne à nouveau au lieu de déplacer le curseur. C'est inattendu. Corrigé en remplaçant GotMouseCapture par MouseDoubleClick qui est commun. Merci à ces dernières solutions de MSDN.
norekhov
1
Cela ne semble pas fonctionner lorsque la zone de texte reçoit le focus initial via FocusManager.FocusedElement. Des idées pourquoi?
szx
24

Bien que ce soit une vieille question, je viens d'avoir ce problème mais je l'ai résolu en utilisant un comportement attaché, plutôt qu'un comportement d'expression comme dans la réponse de Sergey. Cela signifie que je n'ai pas besoin d'une dépendance System.Windows.Interactivitydans le SDK Blend:

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();
    }
}

Vous pouvez ensuite l'utiliser dans votre XAML comme ceci:

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

J'ai blogué à ce sujet ici .

Dutts
la source
J'aime cette approche mais les méthodes Get / Set ne doivent pas se terminer par "Property"; J'ai dû supprimer cela pour obtenir la compilation du code après avoir ajouté la partie Xaml.
Patrick Quirk
Très agréable, a fonctionné comme prévu. J'aime cela, car cela m'aide à séparer les problèmes de vue lors de l'exécution de MVVM.
Killnine
16

Voici une très bonne solution très simple sur MSDN :

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

Voici le code derrière:

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
la source
1
Essentiellement, c'est la même solution que la plus cotée de ce fil. Mais depuis deux ans plus tôt, maintenant je sais d'où @Donnelle l'a emprunté;)
Sergey Aldoukhov
Cette solution m'a semblé la plus simple et a fonctionné pour moi. Je voulais un sous-ensemble de texte spécifique sélectionné par défaut lors de l'entrée dans la zone de texte.
Jack B Nimble
10

Je pense que cela fonctionne bien:

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);
}

Si vous souhaitez l'implémenter comme méthode d'extension:

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

Et dans votre GotFocusévénement:

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

J'ai découvert la solution ci-dessus car il y a plusieurs mois, je cherchais un moyen de fixer le focus sur une donnée UIElement. J'ai découvert le code ci-dessous quelque part (un crédit est accordé) et cela fonctionne bien. Je le poste même s'il n'est pas directement lié à la question du PO car il montre le même schéma d'utilisation Dispatcherpour travailler avec a 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
la source
Je suppose que c'est la méthode la plus simple à mettre en œuvre. après avoir créé la méthode d'extension, vous n'aurez qu'à appeler myTextBox.SelectAllText (). Pourquoi cette réponse n'a-t-elle pas reçu plus de points? pourquoi les autres solutions sont-elles tellement meilleures?
Tono Nam
2
J'éviterais cette méthode car elle repose sur un appel asynchrone pour s'exécuter après le gestionnaire MouseUp de la zone de texte. Je ne ferais pas confiance à ce que ce soit 100% déterministe, et cela pourrait conduire à un comportement incohérent. Même s'il est peu probable que cela se produise, je préfère utiliser les méthodes infaillibles ci-dessus.
Rob H
6

Voici une tentative de résoudre certains des problèmes avec d'autres solutions:

  1. L'utilisation du menu contextuel du clic droit pour couper / copier / coller sélectionne tout le texte même si vous ne l'avez pas tout sélectionné.
  2. Lorsque vous revenez du menu contextuel du clic droit, tout le texte est toujours sélectionné.
  3. Lorsque vous revenez à l'application avec Alt+ Tab, tout le texte est toujours sélectionné.
  4. Lorsque vous essayez de ne sélectionner qu'une partie du texte au premier clic, tout est toujours sélectionné (contrairement à la barre d'adresse de Google chromes par exemple).

Le code que j'ai écrit est configurable. Vous pouvez choisir sur quelles actions le sélectionner tous les comportements devraient se produire en définissant trois champs: lecture seule SelectOnKeybourdFocus, SelectOnMouseLeftClick, SelectOnMouseRightClick.

L'inconvénient de cette solution est qu'elle est plus complexe et que l'état statique est stocké. Cela semble être une lutte affreuse avec le comportement par défaut du TextBoxcontrôle. Pourtant, cela fonctionne et tout le code est caché dans la classe de conteneur Propriété attachée.

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;
    }
}

Pour attacher la propriété attachée à un TextBox, tout ce que vous avez à faire est d'ajouter l'espace de noms xml ( xmlns) de la propriété attachée et de l'utiliser comme ceci:

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

Quelques notes sur cette solution:

  1. Pour remplacer le comportement par défaut d'un événement souris vers le bas et activer la sélection d'une partie seulement du texte au premier clic, tout le texte est sélectionné lors de l'événement souris vers le haut.
  2. J'ai dû faire face au fait que le se TextBoxsouvient de sa sélection après avoir perdu le focus. J'ai en fait outrepassé ce comportement.
  3. Je devais me rappeler si un bouton de la souris était la première action sur le TextBox(FirstActionIsMouseDown champ statique).
  4. Je devais me souvenir du menu contextuel ouvert par un clic droit ( ContextMenuchamp statique).

Le seul effet secondaire que j'ai trouvé, c'est quand SelectOnMouseRightClickc'est vrai. Parfois, le menu contextuel du clic droit scintille lorsqu'il est ouvert et un clic droit sur un espace vide TextBoxne fait pas "tout sélectionner".

Eliahu Aaron
la source
5

Je n'ai trouvé aucune des réponses présentées ici imitant une zone de texte Windows standard. Par exemple, essayez de cliquer dans l'espace blanc entre le dernier caractère de la zone de texte et le côté droit de la zone de texte. La plupart des solutions ici sélectionneront toujours l'intégralité du contenu, ce qui rend très difficile l'ajout de texte à une zone de texte.

La réponse que je présente ici se comporte mieux à cet égard. Il s'agit d'un comportement (il nécessite donc l' assembly System.Windows.Interactivity du SDK Blend ). Il pourrait également être réécrit en utilisant les propriétés attachées.

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;
    }
}

Ceci est basé sur le code que j'ai trouvé ici .

Kristof Verbiest
la source
1
Bien que ce soit une bonne réponse, je pense que lorsque l'utilisateur clique sur l'espace blanc, son intention (dans une application métier) est très probablement de remplacer la valeur entière, donc tout sélectionner est la bonne approche.
Sergey Aldoukhov
1
Sergey: le premier clic sélectionnera la valeur entière, le deuxième clic mettra le curseur à droite de la valeur. Dans les autres solutions présentées, le deuxième clic gardera la valeur entière sélectionnée, ce qui rend très difficile l'ajout à la valeur.
Kristof Verbiest
Comment est-ce utilisé? J'ai ajouté ce code à App.xaml.cs mais il ne semble pas avoir d'effet sur les TextBox de mon application.
PIntag
5

Cette implémentation simple fonctionne parfaitement pour moi:

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;
    }
}

Pour l'appliquer à tous TextBox, mettez le code suivant aprèsInitializeComponent();

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

Dans le fichier App.xaml:

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

Dans le fichier App.xaml.cs:

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

Avec ce code, vous accédez à tous TextBoxdans votre application.

Darshan Faldu
la source
3

Extrait d' ici :

Enregistrez le gestionnaire d'événements global dans le fichier App.xaml.cs:

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

    base.OnStartup(e);
}

Le gestionnaire est alors aussi simple que:

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

Je me rends compte que c'est très ancien, mais voici ma solution qui est basée sur les espaces de nom expressions / interactivité microsoft et interactions.

Tout d'abord, j'ai suivi les instructions de ce lien pour placer les déclencheurs d'interactivité dans un style.

Ensuite, cela revient à cela

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

et ça

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;
  }
}

Dans mon cas, j'ai un contrôle utilisateur où se trouvent les zones de texte qui ont un code-behind. Le code-behind a la fonction de gestionnaire. J'ai donné à mon contrôle utilisateur un nom en XAML, et j'utilise ce nom pour l'élément. Cela fonctionne parfaitement pour moi. Appliquez simplement le style à n'importe quelTextBox endroit où vous souhaitez que tout le texte soit sélectionné lorsque vous cliquez sur TextBox.

Le premier CallMethodActionappelle la SelectAllméthode de la zone de texte lorsque leGotKeyboardFocus événement se TextBoxdéclenche.

J'espère que ça aide.

wiyosaya
la source
Comme il s'agit d'une question tellement ancienne, cela pourrait aider votre réponse à attirer l'attention si vous mentionnez pourquoi quelqu'un pourrait choisir cette approche.
divibisan
Tout d'abord, cela n'a pas besoin d'être mis dans un style, mais je pense qu'il est évident qu'il existe de nombreux contrôles de zone de texte qui en ont besoin, un style est la voie à suivre.
wiyosaya
1
Certains ne seront peut-être pas d'accord avec cette approche, cependant, quant à la raison pour laquelle vous pourriez utiliser cette approche, elle ne nécessite pas de sous-classer TextBox, d'enregistrer des événements de gestionnaire de classe, des méthodes d'extension, de créer des propriétés attachées, etc. En tant que style, il pourrait également être ajouté dans le dictionnaire de ressources de tout projet xaml. Sans la x: Key, elle serait appliquée à n'importe quelle instance de TextBox dans le cadre du dictionnaire de ressources sans avoir à modifier le xaml de chaque zone de texte individuelle. Dans certains cas, il peut s'agir d'une approche plus propre.
wiyosaya
2

J'ai utilisé la réponse de Nils mais converti en plus flexible.

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);
    }
}

En XAML, vous pouvez utiliser comme l'un d'eux:

<!-- 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
la source
1
Vraiment une bonne solution pour une utilisation dans les modèles car vous pouvez le lier à xaml sans aucun code réel, juste un comportement étendu de la zone de texte.
Eric Johansson
2

Voici la version C # de la réponse publiée par @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);
}

alors que MyTextBox_GotFocusle gestionnaire d'événements est affecté à l' GotFocusévénement de MyTextBox.

ViRuSTriNiTé
la source
2

J'ai une réponse légèrement simplifiée pour cela (avec juste le PreviewMouseLeftButtonDown événement) qui semble imiter les fonctionnalités habituelles d'un navigateur:

En XAML, vous avez votre TextBoxmot à dire:

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

Dans 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
la source
1
Pourrait vouloir ajouter un événement GotKeyboardFocus avec TextBox.SelectAll () à l'intérieur pour les personnes qui se frayent un chemin dans votre application. Votre solution fonctionne également pour les PasswordBox (puisque les PasswordBox sont des types scellés, ils ne peuvent pas être étendus).
David Sherret
1

Essayez cette méthode d'extension pour ajouter le comportement souhaité à n'importe quel contrôle TextBox. Je ne l'ai pas encore testé intensivement, mais il semble répondre à mes besoins.

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
la source
1

J'ai beaucoup cherché la solution, j'ai trouvé quelques solutions pour tout sélectionner Mais, le problème est que lorsque nous faisons un clic droit et que nous coupons / copions après avoir sélectionné une partie du texte dans la zone de texte, il sélectionne tout même j'ai sélectionné une partie du texte. Pour résoudre ce problème, voici la solution. Ajoutez simplement le code ci-dessous dans l'événement de sélection du clavier. Cela a fonctionné pour moi.

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
la source
1

J'ai eu le même problème. Dans VB.Net, cela fonctionne facilement de cette façon:

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 # (merci à 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
la source
Meilleure solution pour moi, j'ai publié une traduction C # ici: stackoverflow.com/a/48385409/3936440
ViRuSTriNiTy
Pour moi, cette approche échoue parfois à sélectionner du texte. Je pense que c'est une condition de concurrence due à BeginInvoke.
Vimes
Veuillez préciser. La priorité du répartiteur fonctionne comme prévu sur les applications par défaut. Quelle est ta situation? Avez-vous essayé exactement comme décrit? Quelque chose de spécial dans votre solution?
Nasenbaer
1

C'est de loin la solution la plus simple.

Ajoutez un gestionnaire global à l'application (App.xaml.cs) et c'est fait. Vous n'aurez besoin que de quelques lignes de code.

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

    base.OnStartup(e);
}

Utilisez donc la classe EventManager pour enregistrer un gestionnaire d'événements global contre un type (TextBox). Le gestionnaire réel est très simple:

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

Vérifiez ici: WPF TextBox SelectAll on Focus

J'espère que ça aide.

Marlon Assef
la source
1

Pour ceux qui s'intéressent à l'approche de Donnelle / Groky, mais veulent un clic à droite du dernier caractère (mais toujours dans le TextBox) pour placer le curseur à la fin du texte saisi, j'ai trouvé cette solution:

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();
}

La GetRoundedCharacterIndexFromPointméthode est tirée de ce post.

PIntag
la source
1
Fonctionne bien, mais l'événement de double clic ne se déclenche pas
Rodrigo Caballero
En fait, il entre dans l'événement doubleclick mais la propriété OriginalSource est de type TextBoxView. La méthode SelectAllText doit donc être la suivante: private static void SelectAllText (expéditeur d'objet, RoutedEventArgs e) {var textBox = e.OriginalSource as TextBox; if (textBox! = null) {textBox.SelectAll (); System.Diagnostics.Debug.WriteLine ("Selected ALL"); } else if (l'expéditeur est TextBox) {(l'expéditeur est TextBox) .SelectAll (); }
Rodrigo Caballero
1

Après avoir googlé et testé, j'ai trouvé une solution simple qui a fonctionné pour moi.

Vous devez ajouter un gestionnaire d'événements à l' Loadedévénement de votre fenêtre de conteneur:

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

Ensuite, vous devez créer le gestionnaire du référencé RoutedEventHandlerdans le code précédent:

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

Maintenant, vous pouvez ajouter la SelectAll()commande sur les GotFocusgestionnaires d'événements à n'importe quel TextBoxcontrôle séparément:

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

Votre texte est maintenant sélectionné sur focus!

Adapté de la solution Dr. WPF, MSDN Forums

DonBeto97
la source
Je viens d'utiliser: async privé void TBTime_GotFocus (expéditeur d'objet, RoutedEventArgs e) {TextBox tb = (TextBox) e.OriginalSource; attendre 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
la source
Si vous avez 20 zones de texte sur une fenêtre, allez-vous créer 3 méthodes pour chaque zone de texte? Cette approche n'est pas bonne. Jetez un oeil ici: rachel53461.wordpress.com/2011/11/05/…
Alexandru Dicu
0

Cela semble bien fonctionner pour moi. Il s'agit essentiellement d'un récapitulatif de certains messages antérieurs. Je viens de mettre cela dans mon fichier MainWindow.xaml.cs dans le constructeur. Je crée deux gestionnaires, un pour le clavier et un pour la souris, et j'entraîne les deux événements dans la même fonction HandleGotFocusEvent, qui est définie juste après le constructeur dans le même fichier.

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
la source
Agréable et facile, mais semble avoir un problème de timing - tous les autres essais (clic de souris), il désélectionne à nouveau immédiatement ...?
T4NK3R
0

Un moyen simple de remplacer le mouseDown et de tout sélectionner après un double-clic est:

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();
    }
}
Hesse
la source
0

Essayez de mettre cela dans le constructeur de tout contrôle hébergeant votre zone de texte:

Loaded += (sender, e) =>
{
    MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    myTextBox.SelectAll();
}
CodeOtaku
la source
Cette approche ne fonctionne pas lorsque vous placez cela dans un constructeur de fenêtres.
ViRuSTriNiTy
0

S'il y a un événement qui désélectionne du texte pendant que la OnFocussouris est levée, je retarde généralement la sélection de tout.

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

Je les ai tous testés mais seuls les suivants ont fonctionné:

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
la source
4
C'est aussi une mauvaise utilisation obscène des codes de hachage. Je
lirais
3
Et utiliser GetType().Nameau lieu de isou asest assez hacky
RichK
-1

Je vois qu'il y a beaucoup de réponses, mais comme approuvée, les méthodes qui devraient être utilisées sont EditTextBoxGotCapture

avec le code suivant derrière:

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