I have a form containing a TextBox in C# which I set to a string as follows:
textBox.Text = str;
When the form is displayed, why does the text in the texbox appear highlighted/selected?
The text box has a TabIndex of 0 and TabStop set to true. This means that the control will be given focus when the form is displayed.
You can either give another control the 0 TabIndex (if there is one) and give the text box a different tab index (>0), or set TabStop to false for the text box to stop this from happening.
The default behavior of a TextBox in Windows Forms is to highlight all of the text if it gets focused for the first time by tabbing into it, but not if it is clicked into. We can see this in Reflector by looking at the TextBox's OnGotFocus() override:
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();
}
}
}
It's that if statement that is causing the behavior that we don't like. Furthermore, to add insult to injury, the Text property's setter blindly resets that selectionSet variable whenever the text is re-assigned:
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
this.selectionSet = false;
}
}
So if you have a TextBox and tab into it, all the text will be selected. If you click into it, the highlight is removed, and if you re-tab into it, your caret position (and selection length of zero) is preserved. But if we programmatically set new Text, and tab into the TextBox again, then all of the text will be selected again.
If you are like me and find this behavior annoying and inconsistent, then there are two ways around this problem.
The first, and probably the easiest, is to simply trigger the setting of selectionSet by calling DeselectAll() on form Load() and whenever the Text changes:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.textBox2.SelectionStart = this.textBox2.Text.Length;
this.textBox2.DeselectAll();
}
(DeselectAll() just sets SelectionLength to zero. It's actually SelectionStart that flips the TextBox's selectionSet variable. In the above case, the call to DeselectAll() is not necessary since we are setting the start to the end of the text. But if we set it to any other position, like the start of the text, then calling it is a good idea.)
The more permanent way is to create our own TextBox with the desired behavior through inheritance:
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;
}
}
}
You maybe tempted to just not call base.OnGotFocus(), but then we would lose useful functionality in the base Control class. And you might be tempted to not mess with the selectionSet nonsense at all and simply deselect the text every time in OnGotFocus(), but then we would lose the user's highlight if they tabbed out of the field and back.
Ugly? You betcha. But it is what it is.
The answers to this question helped me a lot with a similar problem, but the simple answer is only hinted at with a lot of other complex suggestions. Just set SelectionStart to 0 after setting your Text. Problem solved!
Example:
yourtextbox.Text = "asdf";
yourtextbox.SelectionStart = 0;
You can also choose the tab order for your form's controls by opening:
View->Tab Order
Note that this option is only available in "View" if you have the Form design view open.
Selecting "Tab Order" opens a view of the Form which allows you to choose the desired tab order by clicking on the controls.
To unhighlight a text field, with VS 2013, try init with:
myTextBox.GotFocus += new System.EventHandler(this.myTextBox_GotFocus);
And add the method:
public void myTextBox_GotFocus(object sender, EventArgs e)
{
myTextBox.SelectionLength=0;
}
I haven't tested this on C# but I ran into the same issue using a C++ WIN32 dialog box. Is seems like you can change the behavior by returning FALSE from OnInitDialog() or WM_INITDIALOG. Hope this helps.
Here is what worked for me
public void SetNotes(string notes)
{
notesTextBox.Text = notes;
notesTextBox.Select();
notesTextBox.SelectionLength = 0;
notesTextBox.SelectionStart = notes.Length;//place cursor at end of text
}
Related
I have not dealt with WinForms for a long time.
Now I'm stuck with something trivial but cannot figure it out.
I have a Winform and when a Timer Tick happens I want to show a message in a new form message box:
frmMessage frmM = new frmMessage();
frmM.txtMessage.Text = ConfigurationSettings.AppSettings["Message"];
frmM.Show();
It works but the text in the textbox shows as selected(with a blue background).
I tried
txtMessage.SelectionLength = 0;
Did not help.
Also tried to set focus to a different control, did not help either.
for now, as a workaround, I will use a Label.
This is a consequence of the way TextBox Class is implemented. If a selection is not specifically set, all text will be selected when the control gets focus.
From TextBox.OnGotFocus:
Protected override void OnGotFocus(EventArgs e) {
base.OnGotFocus(e);
If (!selectionSet) {
// We get one shot at selecting when we first get focus. If we don't
// do it, we still want to act Like the selection was set.
selectionSet = true;
// If the user didn't provide a selection, force one in.
If (SelectionLength == 0 && Control.MouseButtons == MouseButtons.None) {
SelectAll();
}
}
Additionally due to the way the SelectionLength Property is implemented, setting that property to zero does not set the selectionSet` flag as it is already zero.
Instead, set the TextBox.SelectionStart Property immediately after setting the text as this will set that flag.
txtMessage.SelectionStart = 0;
However, your work-a-round of using a Label to display a message is much more appropriate than using an input control.
This is not the best answer but it works. You can try this
frmMessage frmM = new frmMessage();
frmM.txtMessage.Text = "";
frmM.txtMessage.AppendText(ConfigurationSettings.AppSettings["Message"]);
frmM.Show();
I have design 1 winform to look like the picture. But I want the highlighted yellow part to be dockable with dockpanel suite reference. Is that do-able or any other suggestion of better design?
Right now the treeview is on the dockpanel and the red box part is a usercontrol placed in the same dockpanel. I tried to put the redbox as another form but I can't place it as it is in the picture. Also, this winform is need to be responsive so I put in the redbox part in a table layout panel.winform design and not familiar actually with the dockpanel suite reference. If there is a beginner tutorial that I can refer to, it would be much appreciated.
Current design:
There are two approach to your problem. First is dirty one and second elegant one. By dirty and elegant i mean way they display. Method they work are both same.
I will explain to you how to do it on empty form and you just implement that in your populated one.
First create new form.
Add 2 or more GroupBoxes to it
Add some items inside them (just to see if it works)
At the top of the each boxes add Button which will toggle visibility
Our form now looks like this and let's look of code behind it.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
public partial class TestForm : Form
{
// This is property
bool ShowFirstGroupBox
{
get
{
// We let user get our property from private variable
return _ShowFirstGroupBox;
}
set
{
// When user change this property we do something based on that
switch(value)
{
case true:
groupBox1.Size = new Size(groupBox1.Width, FirstGroupBoxDefaultHeight);
break;
case false:
groupBox1.Size = new Size(groupBox1.Width, 55);
break;
}
_ShowFirstGroupBox = value;
}
}
bool ShowSecondGroupBox
{
get
{
return _ShowSecondGroupBox;
}
set
{
switch (value)
{
case true:
groupBox2.Size = new Size(groupBox1.Width, FirstGroupBoxDefaultHeight);
break;
case false:
groupBox2.Size = new Size(groupBox1.Width, 55);
break;
}
_ShowSecondGroupBox = value;
}
}
// We store our boxes current state ( TRUE = shown, FALSE = HIDDEN )
bool _ShowFirstGroupBox = true;
bool _ShowSecondGroupBox = true;
// We store our default height for groupboxes
int FirstGroupBoxDefaultHeight;
int SecondGroupBoxDefaultHeight;
public TestForm()
{
InitializeComponent();
// Assigning default height of our groupboxes
FirstGroupBoxDefaultHeight = groupBox1.Height;
SecondGroupBoxDefaultHeight = groupBox2.Height;
}
private void button1_Click_1(object sender, EventArgs e)
{
ShowFirstGroupBox = !(_ShowFirstGroupBox); // This sets our property value to opposite of this boolean
}
private void button1_Click_1(object sender, EventArgs e)
{
ShowSecondGroupBox = !(_ShowSecondGroupBox); // This sets our property value to opposite of this boolean
}
}
}
Now when we have code like this and press button it will collapse groupbox.
NOTE: Controls under groupbox are still on place but just hidden since they are child of groupbox and everything outside of bounds is not visible to user.
This is dirty way since i would like to display it much prettier with MINUS sign on the right side of the groupbox title so i do not have button inside it. To do this you would need to create custom control which inherits groupbox, add button to it and position it in title bar and create event for it. It is easy if you have ever tried creating custom controls but if you haven't and you think dirty approach is okay with you then do not try it.
I have a selection problem with RichTextBox control. If the control contains hidden text, the selection behaves strangely.
If I do a selection with the mouse, sometimes the bug is present, sometimes not. Especially if I select more lines the bug seems to disappear.
But the bug is very annoying if the user tries to select the text with the keyboard.
The issue is the following: Let's say my control has this text:
There is the little upgraded control that hopefully will make a
differnce when it is hidden text the reason
Then let's say we hide words upgraded, hopefully, hidden by applying proper RTF tags:
#"{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}} \viewkind4\uc1\pard\f0\fs17 There is the little \v upgraded \v0 control that \v hopefully \v0 will make a differnce when it is \v hidden \v0 text the reason\par}";
It all looks good, but when the user tries to select the text using the keyboard, selection seems to reset every time a hidden word is reached.
It is crucial for my control to contain that hidden text (some important id's from my objects that are forming the content inside the control are stored as hidden text at special positions, and I can't/don't want to change that).
I am using the following Form, where richTextBox is the RichTextBox in question and RichTextBox_SelectionChanged is the SelectionChanged event handler that we will try to use to fix our issue.
public MainForm()
{
InitializeComponent();
this.richTextBox.Rtf =
#"{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}\viewkind4\uc1\pard\f0\fs17 My \v upgraded \v0 control that \v hopefully \v0 will make it\par}";
this.richTextBox.SelectionChanged += RichTextBox_SelectionChanged;
}
Basically, the idea is simple - use SelectionChanged handler to properly Select hidden data alongside the previous selection.
For that we will have to store the previous selection data:
private class SelectionData
{
public static SelectionData FromStartAndEnd(
Int32 start,
Int32 end)
{
return new SelectionData(
start: start,
length: end - start);
}
public SelectionData(TextBoxBase tb)
: this(
start: tb.SelectionStart,
length: tb.SelectionLength)
{ }
public SelectionData(Int32 start, Int32 length)
{
this.Start = start;
this.Length = length;
}
public readonly Int32 Start, Length;
public Int32 End
{
get
{
return this.Start + this.Length;
}
}
}
in some field:
private SelectionData _previousSelection;
And update/fix selection inside the SelectionChanged hanlder
private void RichTextBox_SelectionChanged(object sender, EventArgs e)
{
var newSelection = new SelectionData(this.richTextBox);
this.SelfUpdateSelection(newSelection);
}
SelfUpdateSelection method would be something like:
private Boolean _isSelectionSelfUpdating = false;
private void SelfUpdateSelection(SelectionData newSelection)
{
if (!this.IsKeyBoardSelection())
{
// Or it will use previous selection when we don't need it.
this._previousSelection = null;
return;
}
if (this._isSelectionSelfUpdating)
return;
this._isSelectionSelfUpdating = true;
try
{
var fixedSelection = this.FixSelection(newSelection);
this.richTextBox.Select(
start: fixedSelection.Start,
length: fixedSelection.Length);
this._previousSelection = fixedSelection;
}
finally
{
this._isSelectionSelfUpdating = false;
}
}
IsKeyBoardSelection for simplicity can be something like the following, though properly detecting selection change source will be more difficult:
private bool IsKeyBoardSelection()
{
// It may not be true, but usually close enough.
return Control.ModifierKeys.HasFlag(Keys.Shift);
}
FixSelection method should compare whether newSelection can be a this._previousSelection and create a new SelectionData that will contain both newSelection, this._previousSelection and the hidden data between them.
You can use something like this:
private SelectionData FixSelection(SelectionData newSelection)
{
if (this._previousSelection == null)
return newSelection;
var start = Math.Min(
newSelection.Start,
this._previousSelection.Start);
var end = Math.Max(
newSelection.End,
this._previousSelection.End);
return SelectionData.FromStartAndEnd(
start: start,
end: end);
}
but it:
Will work only with forward(right arrow) selection - can be fixed by adding some additional logic to FixSelection.
Will also require a bit of additional this._previousSelection handling (like resetting it on FocusLost event) - there are some edge cases, but still nothing impossible.
public MainForm()
{
...
this.richTextBox.LostFocus += RichTextBox_LostFocus;
}
private void RichTextBox_LostFocus(object sender, EventArgs e)
{
this._previousSelection = null;
}
P.S.: For simplicity I have implemented everything inside the form with fields and form-level handlers, but with some effort it could be made into something reusable (at worst derived RichTextBox, at best some external component that will provide such handling for RichTextBox).
What is the easiest way to recreate the effect where a text box displays a certain string (in italics and different font) until the user has clicked into the control and/or written his own text into the field? For an example, look at the "search" box at the top right of SO.
I have tried consuming the Paint event:
private void textEdit1_Paint(object sender, PaintEventArgs e)
{
if (textEdit1.Text.Length == 0 && !textEdit1.Focused)
{
textEdit1.Font = new Font(textEdit1.Font, FontStyle.Italic);
textEdit1.Text = "123";
}
else
{
textEdit1.Font = new Font(textEdit1.Font, FontStyle.Regular);
textEdit1.Text = string.Empty;
}
}
However, that's not working. By default, it shows no text, and if I click into it, I seem to get an infinite loop of setting the text to "123" and string.empty, until I give another control focus.
So, is that approach even the best, and if yes, what's the correct 2nd condition instead of .Focused?
Try the TextEdit.Properties.NullValuePrompt property. This property provides the text displayed grayed out when the editor doesn't have focus, and its edit value is not set to a valid value.
First of all, you shouldn't use the paint event, you should use the FocusChanged event if you want to do it by modifying the text property. However, the simplest method is not to modify the text property, but draw a string on top, like this:
private void textEdit1_Paint(object sender, PaintEventArgs e)
{
if (textEdit1.Text.Length == 0 && !textEdit1.Focused)
{
Font some_font = new Font(...parameters go here...);
Brush some_brush = Brushes.Gray; // Or whatever color you want
PointF some_location = new PointF(5,5); // Where to write the string
e.Graphics.WriteString("some text", some_font, some_brush, some_location);
}
}
So, if there is no text, and text box is not focused, draw this string. There are many overloads of the WriteString function, so you can pick which one you want.
You can use the Enter event. Set Text property to "search" for example. Use your font like others reported. Then catch the Enter event and set the Text property to string.empty.
textedit1.Text = "search";
private void textEdit1_Enter(object sender, EnterEventArgs e)
{
textedit1.text = string.empty;
}
But i think the best practice is the NullValuePrompt.
Does anyone know which property sets the text color for disabled control?
I have to display some text in a disabled TextBox and I want to set its color to black.
NOTE: see Cheetah's answer below as it identifies a prerequisite to get this solution to work. Setting the BackColor of the TextBox.
I think what you really want to do is enable the TextBox and set the ReadOnly property to true.
It's a bit tricky to change the color of the text in a disabled TextBox. I think you'd probably have to subclass and override the OnPaint event.
ReadOnly though should give you the same result as !Enabled and allow you to maintain control of the color and formatting of the TextBox. I think it will also still support selecting and copying text from the TextBox which is not possible with a disabled TextBox.
Another simple alternative is to use a Label instead of a TextBox.
Additionally, in order for ForeColor to be obeyed on a TextBox marked ReadOnly, you must explicitly set the BackColor. If you want to have it still use the default BackColor, you have to make the set explicit, as the designer is too smart for its own good here. It is sufficient to set the BackColor to its current value. I do this in the Load event for the form, like so:
private void FormFoo_Load(...) {
txtFoo.BackColor = txtFoo.BackColor;
}
I've just found a great way of doing that. In my example I'm using a RichTextBox but it should work with any Control:
public class DisabledRichTextBox : System.Windows.Forms.RichTextBox
{
// See: http://wiki.winehq.org/List_Of_Windows_Messages
private const int WM_SETFOCUS = 0x07;
private const int WM_ENABLE = 0x0A;
private const int WM_SETCURSOR = 0x20;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (!(m.Msg == WM_SETFOCUS || m.Msg == WM_ENABLE || m.Msg == WM_SETCURSOR))
base.WndProc(ref m);
}
}
You can safely set Enabled = true and ReadOnly = false, and it will act like a label, preventing focus, user input, cursor change, without being actually disabled.
See if it works for you.
Greetings
hi
set the readonly attribute to true from the code side or run time not from the design time
txtFingerPrints.BackColor = System.Drawing.SystemColors.Info;
txtFingerPrints.ReadOnly = true;
You can try this.
Override the OnPaint event of the TextBox.
protected override void OnPaint(PaintEventArgs e)
{
SolidBrush drawBrush = new SolidBrush(ForeColor); //Use the ForeColor property
// Draw string to screen.
e.Graphics.DrawString(Text, Font, drawBrush, 0f,0f); //Use the Font property
}
set the ControlStyles to "UserPaint"
public MyTextBox()//constructor
{
// This call is required by the Windows.Forms Form Designer.
this.SetStyle(ControlStyles.UserPaint,true);
InitializeComponent();
// TODO: Add any initialization after the InitForm call
}
Refrence
Or you can try this hack
In Enter event set the focus
int index=this.Controls.IndexOf(this.textBox1);
this.Controls[index-1].Focus();
So your control will not focussed and behave like disabled.
If you want to display text that cannot be edited or selected you can simply use a label
In addition to the answer by #spoon16 and #Cheetah, I always set the tabstop property to False on the textbox to prevent the text from being selected by default.
Alternatively, you can also do something like this:
private void FormFoo_Load(...) {
txtFoo.Select(0, 0);
}
or
private void FormFoo_Load(...) {
txtFoo.SelectionLength = 0;
}
Just handle Enable changed and set it to the color you need
private void TextBoxName_EnabledChanged(System.Object sender, System.EventArgs e)
{
((TextBox)sender).ForeColor = Color.Black;
}
Setting the 'Read Only' as 'True' is the easiest method.