Hành vi mặc định của một TextBox trong Windows Forms là để làm nổi bật tất cả các văn bản nếu nó được tập trung cho lần đầu tiên bằng cách chạm vào nó, nhưng không phải nếu nó được nhấp vào. Chúng ta có thể thấy điều này trong Reflector bằng cách nhìn vào OnGotFocus()
ghi đè các 's TextBox
:
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();
}
}
}
Đó chính là câu lệnh if đó gây ra hành vi mà chúng ta không thích. Bên cạnh đó, để thêm sự xúc phạm đến thương tích, setter các Text
sở hữu của một cách mù quáng reset rằng selectionSet
biến bất cứ khi nào văn bản được giao lại:
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
this.selectionSet = false;
}
}
Vì vậy, nếu bạn có một TextBox và tab vào nó, tất cả các văn bản sẽ được chọn. Nếu bạn nhấp vào nó, đánh dấu sẽ bị xóa và nếu bạn tái tab vào vị trí đó, vị trí dấu mũ của bạn (và độ dài lựa chọn bằng 0) sẽ được giữ nguyên. Nhưng nếu chúng ta lập trình mới Text
và tab lại vào TextBox, thì tất cả văn bản sẽ được chọn lại.
Nếu bạn đang như tôi và thấy hành vi này gây phiền nhiễu và không phù hợp, sau đó có hai cách giải quyết vấn đề này.
Đầu tiên, và có lẽ là dễ nhất, chỉ đơn giản là kích hoạt các thiết lập của selectionSet
bằng cách gọi DeselectAll()
vào mẫu Load()
và bất cứ khi nào Text
thay đổi:.
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.textBox2.SelectionStart = this.textBox2.Text.Length;
this.textBox2.DeselectAll();
}
(DeselectAll()
chỉ đặt SelectionLength
để zero Nó thực sự SelectionStart
Trong trường hợp trên, các cuộc gọi đến DeselectAll()
là không cần thiết vì chúng tôi đang thiết lập bắt đầu để kết thúc văn bản.Nhưng nếu chúng ta đặt nó vào bất kỳ vị trí nào khác, như bắt đầu của văn bản , sau đó gọi nó là một ý tưởng tốt)
Cách lâu dài hơn là tạo ra TextBox riêng của chúng tôi với các hành vi mong muốn thông qua thừa kế:.
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;
}
}
}
Bạn có thể bị cám dỗ để chỉ không gọi base.OnGotFocus()
, nhưng sau đó chúng tôi sẽ mất rất hữu ích chức năng trong lớp cơ sở Control
. Và bạn có thể bị cám dỗ không gây rối với sự vô nghĩa của selectionSet
và chỉ đơn giản là bỏ chọn văn bản mỗi lần trong OnGotFocus(), nhưng sau đó chúng tôi sẽ đánh mất điểm nổi bật của người dùng nếu chúng bị loại ra khỏi trường và quay lại.
Xấu xí? Bạn betcha. Nhưng đó là những gì nó được.
Câu hỏi của bạn có thể liên quan đến http://stackoverflow.com/ câu hỏi/1140250/cách xóa bỏ tập trung từ một hộp văn bản-trong-c-winforms – DarenW
Bạn có sắp xếp việc này không? Làm thế nào bạn sửa lỗi này? – fletcher
@fletcher: Tôi chưa có vòng để xem nó. Tôi sẽ trả lời câu trả lời trong vài ngày nữa. – CJ7