Is it possible to force a textbox in a windows forms application to work in "overwrite mode", i.e. have characters replaced when the user types instead of added?
Otherwise, is there a standard way to get this behavior?
Try using a MaskedTextBox and set InsertKeyMode to InsertKeyMode.Overwrite.
MaskedTextBox box = ...;
box.InsertKeyMode = InsertKeyMode.Overwrite;
If you do not wish to use a Masked textbox you can do this when handling the KeyPress event.
private void Box_KeyPress(object sender, KeyPressEventArgs e)
{
TextBox Box = (sender as TextBox);
if (Box.SelectionStart < Box.TextLength && !Char.IsControl(e.KeyChar))
{
int CacheSelectionStart = Box.SelectionStart; //Cache SelectionStart as its reset when the Text property of the TextBox is set.
StringBuilder sb = new StringBuilder(Box.Text); //Create a StringBuilder as Strings are immutable
sb[Box.SelectionStart] = e.KeyChar; //Add the pressed key at the right position
Box.Text = sb.ToString(); //SelectionStart is reset after setting the text, so restore it
Box.SelectionStart = CacheSelectionStart + 1; //Advance to the next char
}
}
Standard way would be to select the existing text as you land in the textbox, then as the user types it will automatically replace the existing text
This code seems to have an error. I found that you need to set e.Handled in the Keypress event, otherwise the character is inserted twice. Here is my code (in VB) based on the above: -
Private Sub txtScreen_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtScreen.KeyPress
If txtScreen.SelectionStart < txtScreen.TextLength AndAlso Not [Char].IsControl(e.KeyChar) Then
Dim SaveSelectionStart As Integer = txtScreen.SelectionStart
Dim sb As New StringBuilder(txtScreen.Text)
sb(txtScreen.SelectionStart) = e.KeyChar
'Add the pressed key at the right position
txtScreen.Text = sb.ToString()
'SelectionStart is reset after setting the text, so restore it
'Advance to the next char
txtScreen.SelectionStart = SaveSelectionStart + 1
e.Handled = True
End If
End Sub
You could use a RichTextBox instead of a TextBox.
Source:
https://social.msdn.microsoft.com/Forums/en-US/966c3af9-6674-4f48-b487-7afbef05f0cb/overwrite-mode-in-a-textbox
thanks for all! this is mine now. ref :
https://www.syncfusion.com/faq/windowsforms/textbox/how-can-i-place-a-textbox-in-overwrite-mode-instead-of-insert-mode
int surrogate = 0;
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!insertMode)
{
if (char.IsSurrogate(e.KeyChar))
{
surrogate++;
if (surrogate % 2 != 0)
{
return;
}
surrogate = 0;
}
if (textBox1.Text.Length != textBox1.MaxLength && textBox1.SelectedText == ""
&& textBox1.Text != "" && textBox1.SelectionStart != textBox1.Text.Length)
{
textBox1.SelectionLength = 1;//對於已經輸入完成的 surrogate C#應該會正確判斷其字長度;實際測試非然也
//for surrogate pairs input this is necessary or it will cut the pairs in wrong way above
if (char.IsSurrogate(textBox1.SelectedText.ToCharArray()[0]))
{
textBox1.SelectionLength = 2;
}
}
}
}
感恩感恩 南無阿彌陀佛
my applied repo :
https://github.com/oscarsun72/TextForCtext.git
WindowsFormsApp1/Form1.cs
阿彌陀佛
Not sure if using the KeyPress event messes up the normal overtype process, or maybe something specific being checked for within KeyPress, but this isn't quite how a normal windows text box should behave, in that when you start typing in a control with highlighted text, the selection should be removed, allowing you to type in that emptied space. Once I saw the If statement I realised the behaviour I was looking for was accomplished doing this:
If tb.SelectionStart < tb.TextLength AndAlso Not [Char].IsControl(e.KeyChar) Then
tb.SelectedText = ""
End If
not sure why you would want to preserve the selection, but the previous code is ideal if that's what you need
Sal
Related
Right, so I have 13 textboxes with corresponding labels that are assigned after a user decides the name from a different form (instantiated by the 'Add field...' button). The issue arises when the user wishes to delete a textbox with previously entered data, as this results in an empty space where the textbox and label originally were as visualized by the following image:
My question is: how do I make it so that when a user chooses to delete a textbox, the textbox-label pair(s) that follow it replace the deleted textbox AND shift the remaining textboxes accordingly.
Textbox-label pairs in designer:
I've thought about this problem intensively over the past few days, and have concluded that with my current knowledge of C# I am limited to solving this issue with a horrendously tedious amount of if-statements (talking hundreds - thousands here). Any and all help would be appreciated!
Current code on the X-button for first textbox-label pair:
private void xButton1_Click(object sender, EventArgs e)
{
label14.Text = "";
textBox1.Text = "";
if (label14.Text.Equals(""))
{
label14.Visible = false;
textBox1.Visible = false;
xButton.Visible = false;
label14.Text = "";
textBox1.Text = "";
}
if (!textBox2.Text.Equals(""))
{
label14.Text = label15.Text;
textBox1.Text = textBox2.Text;
}
if (!textBox2.Text.Equals("") && (textBox3.Text.Equals("")))
{
label15.Visible = false;
textBox2.Text = "";
textBox2.Visible = false;
xButton2.Visible = false;
}
}
One simple thing you could do is give all your "dynamic" controls (label, textbox, button) a similar value in their Tag property (in my example, I used the string "dynamic" for all the control Tags. This enables you to query for them easily.
Next, you could follow the logic that, anytime you delete some controls, you move all controls below the deleted ones up a distance equal to the height of the control being deleted plus whatever padding you have between the controls.
For example, when a user clicks the X button, since you know the value of the Bottom of the control that's being deleted, you could find all controls that had a matching Tag property whose Top is greater than the x button Bottom, and you can move them up.
Here's an example (this assumes that all your X buttons are mapped to this same click event):
private void buttonX_Click(object sender, EventArgs e)
{
// This is represents the distance between the bottom
// of one control to the top of the next control
// Normally it would be defined globally, and used when you
// lay out your controls.
const int controlPadding = 6;
var xButton = sender as Button;
if (xButton == null) return;
var minTopValue = xButton.Bottom;
var distanceToMoveUp = xButton.Height + controlPadding;
// Find all controls that have the Tag and are at the same height as the button
var controlsToDelete = Controls.Cast<Control>().Where(control =>
control.Tag != null &&
control.Tag.ToString() == "dynamic" &&
control.Top == xButton.Top)
.ToList();
// Delete the controls
controlsToDelete.ForEach(Controls.Remove);
// Get all controls with the same tag that are below the deleted controls
var controlsToMove = Controls.Cast<Control>().Where(control =>
control.Tag != null &&
control.Tag.ToString() == "dynamic" &&
control.Top > minTopValue);
// Move each control up the specified amount
foreach (var controlToMove in controlsToMove)
{
controlToMove.Top -= distanceToMoveUp;
}
}
I need to write the algorithm that replaces the first character by the same character but in upper case. So, I have written this code:
private void RegionFilter_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox tb = (sender as TextBox);
var initialText = tb.Text;
if (initialText != "")
{
var firstChar = initialText.Substring(0, 1).ToUpper();
var restOfString = initialText.Substring(1, initialText.Length - 1);
tb.Text = firstChar + restOfString;
}
}
But there is a problem: The caret doesn't move to the end after replacing the text, it still remains at the beginning.
It's important to say that there is no CaretIndex property in TextBox in Windows Phone 8.
How can I solve this?
You can, however, use the selection methods of the textbox like i have shown here:
myTextBox.Select(tbPositionCursor.Text.Length, 0);
You can find more information about this here::
http://msdn.microsoft.com/en-us/library/ms752349(v=vs.110).aspx
You can also change the position of the caret by setting TextBox.SelectionStart of your TextBox. Add at the end of your algorithm:
yourTextBox.SelectionStart = yourTextBox.Text.Length;
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to prevent richTextBox to paste images within it?
If you're using Richtextbox, there are several advantages in Richtextbox for example:
we can use color font on it
Setting custom font in a region
Attach files on it.. etc
take a look at the picture:
Here is my problem:
Can i just make it text only?
In my project, attach file or the like is unnecessary at all. I even didn't want attach or paste an images on it, i just want "text only" on Richtextbox
How can i do that?
Since RichTextBox doesn't have a Images or Objects collection you have to go for the RTF formatting codes. All data of RichTextBox is stored as plain text with special formatting codes, this is exposed by the control through its RTF property. Learning this code language is essential if you want to read or change it, learning resources are easily available throughout the web, see for example this overview. RichTextBox uses more simplified rtf codes than several full-feature editors like MS Word etc, so it is usually beneficial to load data into a RTB before manipulating it, this will remove much redundant data.
Making a long story short, I found that it is necessary to search for rtf groups that start with either "pict" or "object" command. Knowing that groups may be nested you can't just find the first end-group char from there, you have to parse the string char by char while keeping count of grouping to find the end of those groups. Now you have enough information to remove that part of the string. Rtf may contain multiple picture/object groups so you have to do this until all are removed. Here is a sample function that return rtf string after removing those groups:
private string removeRtfObjects(string rtf)
{
//removing {\pict or {\object groups
string pattern = "\\{\\\\pict|\\{\\\\object";
Match m = Regex.Match(rtf, pattern);
while (m.Success) {
int count = 1;
for (int i = m.Index + 2; i <= rtf.Length; i++) {
//start group
if (rtf(i) == '{') {
count += 1;
//end group
} else if (rtf(i) == '}') {
count -= 1;
}
//found end of pict/object group
if (count == 0) {
rtf = rtf.Remove(m.Index, i - m.Index + 1);
break; // TODO: might not be correct. Was : Exit For
}
}
m = Regex.Match(rtf, pattern);
//go again
}
return rtf;
}
When should this be done? You have already mention Paste, there is also Insert, these can be trapped with the KeyDown event where you get the clipboard info and handle it accordingly. Setting e.Handled=True when you have handled the operation yourself signals that the control should not do any default processing for this key combination. This is also how you block pasting images without destroying the users clipboard. Example:
private void RichTextBox1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
//aware of Paste or Insert
if (e.Control && e.KeyCode == Keys.V || e.Shift && e.KeyCode == Keys.I) {
if (Clipboard.ContainsImage || Clipboard.ContainsFileDropList) {
//some images are transferred as filedrops
e.Handled = true;
//stops here
} else if (Clipboard.ContainsData(DataFormats.Rtf)) {
RichTextBox rtbox = new RichTextBox();
//use a temp box to validate/simplify
rtbox.Rtf = Clipboard.GetData(DataFormats.Rtf);
this.RichTextBox1.SelectedRtf = this.removeRtfObjects(rtbox.Rtf);
rtbox.Dispose();
e.Handled = true;
}
}
}
Yes, it is possible.
Handle Ctrl+V in RichTextBox1_KeyDown, then check the data format in the Clipboard: if data is plain text, paste it; if data is RTF, convert it to plain text (in a buffer without changing the Clipboard content) and paste it; don't paste any other type of data.
This is a partial example just to show you how to proceed:
private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.V)
{
// suspend layout to avoid blinking
richTextBox2.SuspendLayout();
// get insertion point
int insPt = richTextBox2.SelectionStart;
// preserve text from after insertion pont to end of RTF content
string postRTFContent = richTextBox2.Text.Substring(insPt);
// remove the content after the insertion point
richTextBox2.Text = richTextBox2.Text.Substring(0, insPt);
// add the clipboard content and then the preserved postRTF content
richTextBox2.Text += (string)Clipboard.GetData("Text") + postRTFContent;
// adjust the insertion point to just after the inserted text
richTextBox2.SelectionStart = richTextBox2.TextLength - postRTFContent.Length;
// restore layout
richTextBox2.ResumeLayout();
// cancel the paste
e.Handled = true;
}
}
Ok, what I have going on is a textbox that has been filled with some text depending on what was selected from a listbox.
say the textbox looks like this:
blah blah ??? as?f
what I need to figure out how to do is whenever the user clicks in the textbox and deletes a "?" character, I would like to replace that character with an * and then whenever they try to delete the * it will be replaced by a "?" , so that the end result will look something like
blah blah **? as*f
if they deleted all but one "?".
No matter how long I have searched online I cannot seem to find anything similar.. the closest thing I have found is this question - Determine when and which character is added or deleted in a Text Box
But that doesnt really help for what I am trying to do.. if anyone has a good idea on where to start looking or even how to do it I would be very greatfull!
thanks in advance!
EDIT: Yes, this is for a Windows Form application, sorry i forgot to specify that. O.o
You can handle KeyDown event and bypass default handling. The event handler can look like the following:
public void OnKeyDown(Object sender, KeyEventArgs e)
{
char[] text = textBox.Text.ToCharArray();
int pos = textBox.SelectionStart;
switch (e.KeyCode)
{
case Keys.Back: if (pos == 0) return; pos --; break;
case Keys.Delete: if (pos == text.Length) return; break;
default: return;
}
switch (text[pos])
{
case '?': text[pos] = '*'; break;
case '*': text[pos] = '?'; break;
default: return;
}
textBox.Text = new String(text);
e.Handled = true;
}
You may also want to add checks for modifier keys, adjust cursor position, and implement custom behavior when text is selected, if needed.
Store textbox.Text in some string, after each key press (textbox.KeyPress) by comparing saved string with text inside textbox, find out if '?' was deleted, if it was insert '*' into textbox text on the right place.
//get indexes of all '?'
list<int> charlist = new list<int>();
string buff = textbox.Text;
for(int c = 0; c< buff.length, c++)
{
if (buff[c] == '?')
{
charlist.add(c)
}
}
//inside keypress event
foreach(int c in charlist)
{
if (textbox.Text[c] != '?')
{
textbox.Text = textbox.Text.Insert(c, "*");
}
}
I am programatically adding text in a custom RichTextBox using a KeyPress event:
SelectedText = e.KeyChar.ToString();
The problem is that inserting text in such a way doesn't trigger the CanUndo flag.
As such, when I try to Undo / Redo text (by calling the Undo() and Redo() methods of the textbox), nothing happens.
I tried programatically evoking the KeyUp() event from within a TextChanged() event, but that still didn't flag CanUndo to true.
How can I undo text that I insert without having to create lists for Undo and Redo operations ?
Thanks
I finally decided to create my own undo-redo system using stacks.
Here's a quick overview of how I did it :
private const int InitialStackSize = 500;
private Stack<String> undoStack = new Stack<String>(InitialStackSize);
private Stack<String> redoStack = new Stack<String>(InitialStackSize);
private void YourKeyPressEventHandler(...)
{
// The user pressed on CTRL - Z, execute an "Undo"
if (e.KeyChar == 26)
{
// Save the cursor's position
int selectionStartBackup = SelectionStart;
redoStack.Push(Text);
Text = undoStack.Pop();
// Restore the cursor's position
SelectionStart = selectionStartBackup;
}
// The user pressed on CTRL - Y, execute a "Redo"
if (e.KeyChar == 25)
{
if (redoStack.Count <= 0)
return;
// Save the cursor's position
int selectionStartBackup = SelectionStart + redoStack.ElementAt(redoStack.Count - 1).Length;
undoStack.Push(Text);
Text = redoStack.Pop();
// Restore the cursor's position
SelectionStart = selectionStartBackup;
return;
}
undoStack.Push(Text);
SelectedText = e.KeyChar.ToString();
}
It's just an idea but what if you set the caret position to where you would insert your text and instead of modifying the Text property, just send the keys?
SendKeys.Send("The keys I want to send");
There are bound to be quirks but as I said, it's just an idea.
You can use TestBox.Paste. The documentation in the class overview, saying "Sets the selected text to the specified text without clearing the undo buffer.", seems confusing. I have just tried it and it sets the Undo as expected.
Is spite of its name it has no relation to Clipboard at all, it just replaces the currently selected text with the text you provide as an argument, and therefore seems just to do what the question asks for, in very simple manner.