160 votes

Faire en sorte qu'une TextBox WinForms se comporte comme la barre d'adresse de votre navigateur

Lorsqu'une zone de texte WinForms C# reçoit le focus, je veux qu'elle se comporte comme la barre d'adresse de votre navigateur.

Pour voir ce que je veux dire, cliquez dans la barre d'adresse de votre navigateur web. Vous remarquerez le comportement suivant :

  1. Un clic dans la zone de texte devrait sélectionner tout le texte si la zone de texte n'était pas précédemment focalisée.
  2. Le fait d'appuyer sur la souris et de la faire glisser dans la zone de texte devrait sélectionner uniquement le texte que j'ai mis en évidence avec la souris.
  3. Si la zone de texte est déjà focalisée, le fait de cliquer ne permet pas de sélectionner tout le texte.
  4. Le fait de mettre l'accent sur la zone de texte de manière programmatique ou par le biais de la tabulation du clavier devrait permettre de sélectionner tout le texte.

Je veux faire exactement cela dans WinForms.

ALERTE SUR LE PISTOLET LE PLUS RAPIDE : veuillez lire ce qui suit avant de répondre ! Merci les gars. :-)

L'appel de .SelectAll() pendant l'événement .Enter ou .GotFocus ne fonctionnera pas fonctionnera pas car si l'utilisateur a cliqué sur le bouton boîte de texte, le signe d'insertion sera placé où il a cliqué, désélectionnant ainsi tout le texte. texte.

L'appel de .SelectAll() pendant l'événement .Click ne fonctionne pas car l'utilisateur ne pourra pas sélectionner de texte avec la souris ; l'appel .SelectAll() continuera à écraser la sélection de texte de l'utilisateur.

L'appel de BeginInvoke((Action)textbox.SelectAll) sur l'événement focus/entrée ne fonctionne pas parce qu'elle enfreint la règle n° 2 ci-dessus, elle continuera à remplacer la sélection de l'utilisateur au moment du focus.

3 votes

Veuillez préciser que c'est pour une "RichTextBox".

0 votes

Nescio, une zone de texte ou une zone de texte enrichi fera l'affaire. J'ai aussi essayé votre solution sur une zone de texte.

0 votes

C'est une fuite d'abstraction. La meilleure façon de procéder est de marquer WM_MOUSEACTIVATE et SelectAll sur WM_SETFOCUS s'il n'est pas WM_MOUSEACTIVATE-ing.

111voto

Judah Himango Points 27365

Tout d'abord, merci pour les réponses ! 9 réponses au total. Merci.

Mauvaise nouvelle : toutes les réponses comportaient des bizarreries ou ne fonctionnaient pas tout à fait correctement (ou pas du tout). J'ai ajouté un commentaire à chacun de vos messages.

Bonne nouvelle : j'ai trouvé un moyen de le faire fonctionner. Cette solution est assez simple et semble fonctionner dans tous les scénarios (déplacement de la souris vers le bas, sélection de texte, tabulation, etc.)

bool alreadyFocused;

...

textBox1.GotFocus += textBox1_GotFocus;
textBox1.MouseUp += textBox1_MouseUp;
textBox1.Leave += textBox1_Leave;

...

void textBox1_Leave(object sender, EventArgs e)
{
    alreadyFocused = false;
}

void textBox1_GotFocus(object sender, EventArgs e)
{
    // Select all text only if the mouse isn't down.
    // This makes tabbing to the textbox give focus.
    if (MouseButtons == MouseButtons.None)
    {
        this.textBox1.SelectAll();
        alreadyFocused = true;
    }
}

void textBox1_MouseUp(object sender, MouseEventArgs e)
{
    // Web browsers like Google Chrome select the text on mouse up.
    // They only do it if the textbox isn't already focused,
    // and if the user hasn't selected all text.
    if (!alreadyFocused && this.textBox1.SelectionLength == 0)
    {
        alreadyFocused = true;
        this.textBox1.SelectAll();
    }
}

Pour autant que je sache, cela fait en sorte qu'une zone de texte se comporte exactement comme la barre d'adresse d'un navigateur web.

J'espère que cela aidera la prochaine personne qui tentera de résoudre ce problème d'une simplicité trompeuse.

Merci encore, les gars, pour toutes vos réponses qui m'ont aidé à me diriger vers le bon chemin.

0 votes

Qu'en est-il lorsque le focus est programmé sur un TextBox ? J'ai ce problème comme discuté ici : stackoverflow.com/questions/24790704/ J'ai réussi à le résoudre, après un certain temps, mais je suis toujours nerveux à ce sujet, car ma "solution" semble plutôt bancale.

0 votes

Vous avez écrit : "L'appel de .SelectAll() pendant les événements .Enter ou .GotFocus ne fonctionnera pas car si l'utilisateur a cliqué sur la zone de texte, le curseur sera placé là où il a cliqué, désélectionnant ainsi tout le texte." J'ai bien SelectAll dans l'événement GotFocus qui, pour l'essentiel, fonctionne. En fait, je pense que le fait que le curseur soit placé là où l'utilisateur a cliqué est "une bonne chose". Je veux simplement qu'il soit toujours sélectionné lorsque le focus est placé sur la TextBox de manière programmatique.

0 votes

Et je suis de nouveau là ! :)

82voto

Duncan Smart Points 9195

J'ai trouvé une solution plus simple à ce problème. Il s'agit de lancer le SelectAll de manière asynchrone à l'aide de Control.BeginInvoke de manière à ce qu'il se produise après que les événements Entrée et Clic se soient produits :

En C# :

private void MyTextBox_Enter(object sender, EventArgs e)
{
    // Kick off SelectAll asynchronously so that it occurs after Click
    BeginInvoke((Action)delegate
    {
        MyTextBox.SelectAll();
    });
}

En VB.NET (grâce à Krishanu Dey )

Private Sub MyTextBox_Enter(sender As Object, e As EventArgs) Handles MyTextBox.Enter 
    BeginInvoke(DirectCast(Sub() MyTextBox.SelectAll(), Action)) 
End Sub

5 votes

La réponse la plus intelligente que j'aie jamais trouvée Merci beaucoup Pour VB.net, voici la solution Private Sub MyTextBox_Enter(sender As Object, e As EventArgs) Handles MyTextBox.Enter BeginInvoke(DirectCast(Sub() MyTextBox.SelectAll(), Action)) End Sub

0 votes

Classe Much 'La meilleure solution, comme la barre d'URL du navigateur web, beaucoup de classe End Class

7 votes

En .Net 4.0, vous pouvez le faire : BeginInvoke((Action)MyTextBox.SelectAll) ;

30voto

nzhenry Points 266

Votre solution est bonne, mais elle échoue dans un cas précis. Si vous donnez le focus à la TextBox en sélectionnant une plage de texte au lieu de simplement cliquer, l'indicateur alreadyFocussed n'est pas mis à true, donc quand vous cliquez dans la TextBox une seconde fois, tout le texte est sélectionné.

Voici ma version de la solution. J'ai également placé le code dans une classe qui hérite de TextBox, de sorte que la logique est bien cachée.

public class MyTextBox : System.Windows.Forms.TextBox
{
    private bool _focused;

    protected override void OnEnter(EventArgs e)
    {
        base.OnEnter(e);
        if (MouseButtons == MouseButtons.None)
        {
            SelectAll();
            _focused = true;
        }
    }

    protected override void OnLeave(EventArgs e)
    {
        base.OnLeave(e);
        _focused = false;
    }

    protected override void OnMouseUp(MouseEventArgs mevent)
    {
        base.OnMouseUp(mevent);
        if (!_focused)
        {
            if (SelectionLength == 0)
                SelectAll();
            _focused = true;
        }
    }
}

2 votes

+1 pour la suggestion de la boîte de texte personnalisée et la solution qui fonctionne parfaitement !

0 votes

Excellente solution. J'ai copié votre code directement dans ma solution, j'ai changé l'espace de noms pour protéger les innocents, et ça a marché parfaitement. Merci !

8voto

Todd Benning Points 87

C'est un peu compliqué, mais dans votre événement de clic, utilisez SendKeys.Send( "{HOME}+{END}" ); .

0 votes

Woofta ! C'est un peu de la piraterie ! :-) Merci pour la suggestion. Une meilleure idée ?

0 votes

Piratage en effet, mais ça n'a pas l'air mauvais du tout.

3 votes

Il faut savoir que de nombreux programmes antivirus interceptent et bloquent SEND KEYS comme étant malveillant. Ce n'est pas une solution idéale.

4voto

Jakub Kotrla Points 247

Événement de clic de la zone de texte ? Ou même l'événement MouseCaptureChanged fonctionne pour moi. - OK. Cela ne fonctionne pas.

Donc vous devez faire 2 choses :

private bool f = false;

private void textBox_MouseClick(object sender, MouseEventArgs e)
{ 
  if (this.f) { this.textBox.SelectAll(); }
  this.f = false;
}

private void textBox_Enter(object sender, EventArgs e)
{
  this.f = true;
  this.textBox.SelectAll();
}
private void textBox_MouseMove(object sender, MouseEventArgs e) // idea from the other answer
{
  this.f = false; 
}

Cela fonctionne aussi pour la tabulation (à travers les textBoxes jusqu'à l'une d'entre elles) - appelez SelectAll() dans Enter au cas où...

0 votes

Ok Jakub, ça marche partiellement. Si j'utilise la tabulation pour accéder à la zone de texte, celle-ci doit être mise au point. Cela fonctionnera-t-il avec votre solution ? (Si vous pouvez me montrer comment, je marquerai votre réponse comme étant la bonne).

0 votes

Jakub, maintenant que vous avez posté le code, il semble que parfois travail. Pas toujours ; en ce moment, je clique dans la zone de texte et tout n'est pas sélectionné.

0 votes

Parfois, je clique dans le texte et il ne sélectionne pas tout. C'est comme si le champ .f n'était pas défini comme il devrait l'être, et que SelectAll n'était pas appelé. Vous n'avez pas rencontré ce problème ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X