El comportamiento predeterminado de un TextBox en Windows Forms es resaltar todo el texto si se enfoca por primera vez al tabularlo, pero no si se hace clic en él. Podemos ver esto en Reflector examinado OnGotFocus()
anulación del TextBox
's:
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
if (!this.selectionSet)
{
this.selectionSet = true;
if ((this.SelectionLength == 0) && (Control.MouseButtons == MouseButtons.None))
{
base.SelectAll();
}
}
}
Es que si la declaración que está causando el comportamiento que no nos gusta. Además, para colmo de males, organismo de la propiedad Text
restablece ciegamente que selectionSet
variables cada vez que se presenta el texto re-asignado:
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
this.selectionSet = false;
}
}
Así que si usted tiene un cuadro de texto y pestaña en ella, se seleccionará todo el texto. Si hace clic en él, se eliminará el resaltado y, si vuelve a tabular en él, se conservará su posición de intercalación (y la longitud de selección de cero). Pero si configuramos programáticamente el nuevo Text
, y tabulamos en el TextBox de nuevo, todo el texto se volverá a seleccionar.
Si eres como yo y encuentras este comportamiento molesto e incoherente, entonces hay dos formas de solucionar este problema.
La primera, y probablemente el más fácil, es simplemente activar la configuración de selectionSet
llamando DeselectAll()
en forma Load()
y siempre que los Text
cambios:.
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.textBox2.SelectionStart = this.textBox2.Text.Length;
this.textBox2.DeselectAll();
}
(DeselectAll()
simplemente establece SelectionLength
a cero En realidad es SelectionStart
que invierte la variable TextBox
selectionSet
. En el caso anterior, la llamada a DeselectAll()
no es necesaria ya que estamos configurando el inicio hasta el final del texto. Pero si lo configuramos en cualquier otra posición, como el comienzo del texto , luego llamando es una buena idea)
La forma más permanente es crear nuestro propio cuadro de texto con el comportamiento deseado a través de la herencia:.
public class NonSelectingTextBox : TextBox
{
// Base class has a selectionSet property, but its private.
// We need to shadow with our own variable. If true, this means
// "don't mess with the selection, the user did it."
private bool selectionSet;
protected override void OnGotFocus(EventArgs e)
{
bool needToDeselect = false;
// We don't want to avoid calling the base implementation
// completely. We mirror the logic that we are trying to avoid;
// if the base implementation will select all of the text, we
// set a boolean.
if (!this.selectionSet)
{
this.selectionSet = true;
if ((this.SelectionLength == 0) &&
(Control.MouseButtons == MouseButtons.None))
{
needToDeselect = true;
}
}
// Call the base implementation
base.OnGotFocus(e);
// Did we notice that the text was selected automatically? Let's
// de-select it and put the caret at the end.
if (needToDeselect)
{
this.SelectionStart = this.Text.Length;
this.DeselectAll();
}
}
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
// Update our copy of the variable since the
// base implementation will have flipped its back.
this.selectionSet = false;
}
}
}
Usted tal vez la tentación de no llamar base.OnGotFocus()
, pero entonces perdería útil funcionalidad en la clase base Control
. Y es posible que tenga la tentación de no meterse con el absurdo selectionSet
en absoluto y simplemente anule la selección del texto cada vez que lo haga en OnGotFocus(), pero luego perderíamos el resaltado del usuario si saltaran del campo y retrocedieran.
¿Ugly? Puedes apostar. Pero es lo que es.
Su pregunta podría estar relacionado con http://stackoverflow.com/ questions/1140250/how-to-remove-focus-from-a-textbox-in-c-winforms – DarenW
¿Pudo resolver esto? ¿Cómo arreglaste esto? – fletcher
@fletcher: Todavía no he podido verlo. Voy a otorgar la respuesta en unos días. – CJ7