I want to disable selecting text and clicking in the middle of text in a TextBox, but the user must be able to enter this TextBox and write at the end of earlier text, so I cannot make it ReadOnly or Enable = false.
I try to handle MouseDown and do the following:
input.Select(input.Text.Length, 0);
It helps with placing a cursor in the middle of text, but the user still can make a selection from the end.
I also make a MessageBox() on MouseDown event, but in this case the user cannot click on textBox and write anything.
The last try was to set a focus() in another Control and focus back, after a period of time, but it didn't work at all. User still can make a selection.
How can I do it?
How about this for Click event
Edit: Also do the same for DoubleClick and MouseLeave to cover all cases. You can have a common event handler.
private void textBox1_Click(object sender, EventArgs e)
{
((TextBox) sender).SelectionLength = 0;
}
If it fits the UI/user model, another approach is to use two text boxes: a read-only one with the previous text that the user can see and act on (if that is something he needs to do) and an editable one for the new text along with a button to commit the new text to the read-only text box (and persistence layer).
That approach is not only arguably more user-friendly—the editable box is completely editable rather than just "appendable", which gets confusing when the user hits Backspace—but also requires less fighting with the framework to make the boxes do what you need.
You're not far off with your MouseDown event handler, but probably better to catch MouseUp, as this is the event that will fire when they have finished selecting.
Alternatively, you could catch the SelectionChanged event.
Just put your:
input.Select(input.Text.Length, 0);
code in any of those event handlers.
Related
I've got TextBoxes in a C# form. The user enters data, and then when they leave the control (almost always by hitting Tab), I check the data to make sure it's valid. If it is invalid, I want to highlight their text so they can immediately fix it rather than having to click it.
Right now, on Control.Leave, I validate their entry. This works just fine. However, since they hit Tab, right after they dismiss the error message, it goes on to the next object, even though I've got ((TextBox)sender).Focus();
How can I have the above line fire after the form Tabs to the next control.
You may want to look into Control.CausesValidation property
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.causesvalidation(v=vs.110).aspx
You can validate the control prior to the user leaving focus rather than waiting on Focus moving itself.
And here's MSDN documentation for Control.Validating event, does a good job at laying out the sequence of events when gaining / losing focus of a Control.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validating(v=vs.110).aspx
Notice how Control.Validating and Control.Validated are launched prior to Control.LostFocus. You can perform your validation step prior to allowing the user to lose focus of your Textbox.
There's also a pretty good previous answer on stackoverflow.com which outlines how to do this: C# Validating input for textbox on winforms
If you handle the Control.Validating event, setting e.Cancel to true will stop the change of focus from occurring.
Note that this method will also stop buttons from working, so you may need to set Control.CausesValidation to false on certain buttons.
You will also need the following snippet on the main form to allow the close button to work:
protected override void OnFormClosing(FormClosingEventArgs e) {
e.Cancel = false;
base.OnFormClosing(e);
}
Try using the LostFocus event on the TextBox to Focus it again
In my C# Windows form MyForm I have some TextBoxes.
In these TextBoxes, we have to detect if the TextChanged event occurs,
if there're changes in these TextBoxes and click close button, it will ask if we want to cancel the changes when we close the form.
However, when I run the MyForm, I can't know text change for each textbox caused by user typing for without textchanged event property.
But I am thinking how do I make the TextBox's TextChanged know the
event cuased by user typing without textchanged event?
Thanks for help.
Sorry for my English.
There is no (decent) way of knowing what's typed without a TextChanged or a Leave event.
You need to use one of these events to get the typed content. Doing this enable you to set a "dirty" flag that you can check at close and clear at save.
Comparing old and new value has no point without this cause you won't know what the value should be set to without knowing something was changed.
With one exception: If your original data came from a database you could use the compare old/new approach as you would compare the textbox of that which came from the database.
Update:
Addressing this comment:
"Because Myform have many textboxes and if no text change ,this will
not display the confirm message.If I catch textchanged event for all
textboxes, this is so many code."
You can use a common handler to collect the changes for all textboxes in one single method. Use the sender object (cast it to Textbox) to identify which textbox is changed, if needed, or simply set a dirty flag for whatever textbox has a change.
bool isDirty = false;
void SomeInitMethod() //ie. Form_Load
{
textbox1.TextChanged += new EventHandler(DirtyTextChange);
textbox2.TextChanged += new EventHandler(DirtyTextChange);
textbox3.TextChanged += new EventHandler(DirtyTextChange);
//...etc
}
void DirtyTextChange(object sender, EventArgs e)
{
isDirty = true;
}
void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (isDirty) {
//ask user
}
}
// to clear
void Save()
{
SaveMyDataMethod();
isDirty = false;
}
If you have a lot of textboxes in the form loop through the forms control collection and use typeof to address the textboxes. If you have textboxes requiring different approaches use the Tag property of the textbox to distinguish.
A possible approach is using the timer. Have a timer that ticks every 1000 ms (say) and checks the textBox.Text.
A second possible approach is overriding WndProc for the textbox (by inheriting a new class) and handling the change text message. This would be the same as overriding TextBox.OnTextChanged.
Why dont you use a timer which will check after a few intervals if the textboxes do contain any text
I have a listview control in my windows application, which is populated with some set of items. I will make the selection of an item programmatically by setting ListViewItem.Selected property to true. But I want to prevent the user from selecting an item in the listview. i.e., it should be always selected programmatically. I can prevent the user selection by disabling the control, but disabling the control will also disable the scroll bars which is not correct.
Even I have created a custom listview control and implemented a ItemSelectionChanging eventhandler using WndProc check link, using which i can cancel the event as shown below,
private void lstLiveTables_ItemSelectionChanging(object sender, ListViewExItemSelectionChangingEventArgs e)
{
e.Cancel = true;
}
But again, this will cancel the event, even for an item selected programmatically. My question, is there anyway to identify whether the selection is made manually (by user) or programmatically in SelectedIndexChanged or using WndProc Message.
Note: If it is required, I will upload the code of CustomListView control.
Update 1
Thanks emartel. It was a good thought. Even I tried to achieve the same thing by subscribing to the event only before selecting the item and removed it immediately after selecting. By this way, upon selection the event will be immediately triggered and it will continue. This is working fine.
this.lstTables.SelectedIndexChanged += new System.EventHandler(this.lstTables_SelectedIndexChanged);
item.Selected = true;
this.lstTables.SelectedIndexChanged -= new System.EventHandler(this.lstTables_SelectedIndexChanged);
But again I have a problem that, if the user selects an item manually, nothing will happen (no event will be triggered) but the item alone will be highlighted. Once an item is highlighted and if i try to select the same item programmatically nothing is happening i.e., the SelectedIndexChanged event is not getting triggered for that item as it is already highlighted.
Note: Same behavior even if I follow the Flag approach suggested by you.
Update 2
I can solve this issue by having my own method instead of handling through events as emartel's suggestion. But my question is, according to my update 1, is there anyway to trigger the SelectedIndexChanged event when the item is highlighted but not actually selected?
public FrmTest()
{
list.ItemSelectionChanged += list_ItemSelectionChanged;
}
private bool changing;
private void list_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
if (changing)
return;
if (e.Item == nonSelectableListItem)
{
changing = true;
nonSelectableListItem.Selected = false;
changing = false;
}
}
Sample:
Well, an easy solution would be to keep a flag saying that you are programmatically changing the selection and to allow the event to pass, and reset the flag when you're done
Edit: if you, and only you, can change the selection, and you do this programmatically, so you have control over where and when this happens, why do you even need the EventHandler? Why not call a method to do whatever processing you want to happen?
One dirty way to do that is to keep list of selected items and refresh selection every time it changes other way than from your code.
There is also an ItemSelectionChanged event which is raised separately for every item whose selection state have changed. You can probably flip the selection state back it this event.
You may also take a look on Better ListView Express control. It have a read-only mode, so that user cannot change the selection. Its setup is very simple:
listView.ReadOnly = true;
The full version also supports custom non-selectable items. Simply setting:
listView.Items[0].Selectable = false;
make the first non-selectable (by the user).
You can still select items from code, of course.
The following image shows non-selectable items in action (they are marked by gray color):
I have a datagridview with a check box in it. The point is when the user clicks the check box I immediately want to perform an action. The problem I have is, If I process the cell click method this does not work if the user uses the keyboard. I can tie onto the currentcelldirtystatechanged event but this is only raised the first time the cell is changed but not subsequent times. Essentially I want to act immediately and not force the user to change the cell that is currently in focus.
Use the CurrentCellDirtychanged event and the IsCurrentCellDirty property.
// This event handler manually raises the CellValueChanged event
// by calling the CommitEdit method.
void dataGridView1_CurrentCellDirtyStateChanged(object sender,
EventArgs e)
{
if (dataGridView1.IsCurrentCellDirty)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
There is a "CellEnter" event that will be raised when a cell gains focus, however that may happen. The user may not have changed anything yet, but the behavior you describe (clicking on the cell or tabbing/arrowing into it) doesn't require them to.
I have a textbox, a standard button and a toolstrip containing a couple of buttons.
In the validating event of the textbox I coded to check whether it is blank.
If yes then it shows a message 'Enter Value'. When the standard button is clicked while
the textbox is empty, it's validating properly and showing the message but when the
toolstripbutton is clicked it's not validating the textbox and no message is shown. It seems that I've got to write the validation code explicitly in the
toolstripbutton_click event which is too troublesome when there are multiple textboxes and toolstripbuttons on a single form.
What I want to know is whether the textbox_validating can be fired when the toolstripbutton is clicked? Handling toolstrips is really a headache.
The ToolStripItem classes are special, they don't derive from Control. One side-effect of that is that they don't take the focus away from the active control. And that prevents the Validating event from firing.
Several things you can do. You could call the textbox' parent's ValidateChildren() method. Or you could move the focus yourself:
private void toolStripButton1_Click(object sender, EventArgs e) {
btnSave.Focus();
if (btnSave.Focused) btnSave.PerformClick();
}
Write the following in toolstripbutton click event:
Me.Validate()
You can call the textbox_validating procedure from the procedure that handles the toolstripbutton click event, but you may have to add some logic to see if it passed validation before proceeding with the rest of the toolstripbutton_click event. Since you said you have a lot of textboxes to validate, you might want to consider making a Validate() function that returns true or false and checks all of the textboxes. Then all you have to do is check if Validate() = true and call the same function from all of your toolstrip buttons instead of copying the same code over and over again.