Partially read-only textbox in c# - c#

I've got a list of illegal positions and characters that can't move from those positions. How would I prevent those from being modified in the TextChanged event? Every solution I've come up with has been extremely hacky and unreliable, or has relied on the KeyDown event, which doesn't prevent the user from deleting the read-only text in other ways (select the text and delete it, or just press the backspace key).
I've thought of doing something like this:
//CharPos is a class with an int (CharPos.Position) and a char that
//should be at that int's position (CharPos.Ch)
foreach (CharPos p in IllegalPositions)
{
console.Text = console.Text.Remove(p.Position, 1);
console.Text = console.Text.Insert(p.Position, p.Ch.ToString());
}
But it completely messes up and goes on an infinite loop. And even if I stopped it from doing that, it wouldn't work if you changed the character count of the text, by using the delete key for example. Maybe I could use regex somehow? (I dunno, I have no experience at all with regex).

Can you combine multiple TextBoxes (for editable parts) with TextBlocks (for readonly parts)? You would just need to play with styling of the two to match

Could you please check the link below:
Disabling or making it readonly a part of the values in a Text Box (.net)
rtBox.Select(0, (rtBox.Text = "I am fixed content").Length);
rtBox.SelectionProtected = true;
rtBox.AppendText(Environment.NewLine);

Related

C# Increment for loop every time button is pressed

I googled a few things before posting, but I couldn't find anything like this. Basically, I want to take text from a textbox, save as a variable (say history1) to then be able to call that in the future to display the text. I can do that, but what I'm stuck with is that I want 3 variables (history1, history2 and history3, for example) and each time the button is pressed the string is moved to the next variable.
For example, the button is pressed, the text is saved as variable history1. The text is changed and the button is pressed again, the text from history1 is moved to variable history2, and the new text is saved as history1. This would only need to work for 3 instances though, not infinitely, so when text is stored in history3 and the button is pressed the text is just overwritten.
The way I had thought of approaching this was:
string history1;
string history2;
string history3;
for (int i = 1; i < 4; i++)
{
history1 = txtOutput.Text;
btnToFile_Click()
{
history2=history1;
btnToFile_Click()
{
history3=history2;
}
}
}
However, this isn't going to work because the btnToFile_Click doesn't take any arguements. Is there an easier way to go about this or just a way to fix the method not taking arguements ?
Thanks in advance!
Make sure that you delcare history1, history2, and history3 on the form level (not inside any method).
Then, have the following code inside the handler of the click event of the button:
history3 = history2;
history2 = history1;
history1 = txtOutput.Text;
You don't need to call the btnToFile_Click() method multiple times in your loop, just move the text from end textbox to another in reverse order. Nor do you need a loop because you only have three textboxes.
Why reverse order? So you move the value to the next textbox before it is overwritten by the new value.
So:
history3 = history2;
history2 = history1;
history1 = txtOutput.Text;
btnToFile_Click() is a Click event handler for btnToFile (a button). You're not supposed to call that method yourself, it's called by the UI framework (say WPF or WinForms etc.). By the way, it does receive a parameter, then event source (since you can assign the same event handler to multiple buttons and do something based on which one sent the event)
You can try saving in a string array and move the strings within it when you call the button clicked event

Check every TextBox for letters

Lets assume I have 5 TextBoxes like this:
textBox_Box1
textBox_Box2
textBox_Box3
textBox_Box4
textBox_Box5
And I have a function that checks if the TextBox contains only letters, like this:
public static bool OnlyLetters(string s)
{
foreach (char c in s)
{
if (!Char.IsLetter(c))
return false;
}
return true;
}
Is there an efficient way to check every textBox with this function? I do not want to write it in this style of course:
OnlyLetters(textBox_Box1.Text);
OnlyLetters(textBox_Box2.Text);
OnlyLetters(textBox_Box3.Text);
OnlyLetters(textBox_Box4.Text);
OnlyLetters(textBox_Box5.Text);
I would prefer to check it in a loop, but I do not know how to realize it at that point.
You could create an array of your TextBoxes:
private TextBox[] textBoxes = {
textBox_Box1,
textBox_Box2,
textBox_Box3,
textBox_Box4,
textBox_Box5
};
Then you can access it in a loop:
foreach (TextBox txt in textBoxes)
{
if (!OnlyLetters(txt.Text))
{
// Do something
}
}
One way would be to put all your text boxes in some sort of container and then loop through the children of the container (which will be text boxes) and preform a check on each. That way, you can add and remove text boxes from the container as needed without modifying your code.
When you are looping through the text box container, check to see if the child you are on is in fact a text box, then preform a cast on it so you may access it's text property.
I do not know which framework you are using, so I cannot provide a code sample.
You said you would like to check it in a 'Loop'. I don't know what GUI framework you are using so the types might be wrong, but you could do something like the following:
List<TextBox> textBoxes = new List<TextBox>();
// Add all your textBoxes to the list here
Then use a loop on the list of textBoxes whenever you want to check their contents. If it's a mobile platform you should probably see if it's possible to limit the type of keyboard shown, and on iOS you can automatically have the UI components added to the list so you don't have to manually write the code. Hope this helps a bit!

AutoCompleteStringCollection with TextChanged Event

I'm currently using a text box to filter some entries. I have the display updating on the text box TextChanged event, so the user isn't hitting enter or pressing a button to begin filtering. I want to use an AutoCompleteStringCollection to remember entries typed into the text box; however, if I save every string from the text box when the TextChanged event is fired then it will store all the substrings of each filter term.
So for instance, if I typed the string "test" it would display:
"t"
"te"
"tes"
"test"
as recommended strings. I just want the last string added to the AutoCompleteStringCollection.
I've thought about two separate methods I could implement.
1) I could create a Task that waits "x" amount of time after the last TextChanged event before it adds the string to the AutoCompleteStringCollection. If I did this I would have to use a cancellationToken to cancel the Task every time the textChanged event fired. This is slightly more complicated because I'm using .NET 4.0.
2) I could also search through the AutoCompleteStringCollection every time a string is added and remove all substrings (that start at the beginning of the word). This may backfire if the user types in a more specific filter, but still wants to store the shorter one.
Is there a better way to go about doing this? Which method would you recommend?
There are two things to be aware of when trying to dynamically fill the AutoCompleteStringCollection. First is Microsoft's Resolution to the issue:
Do not modify the AutoComplete candidate list dynamically during key events. (MSDN)
Having said that, I was able to figure out a way to dynamically add elements to the list.
I ended up opting for a modified version of the Task implementation. Instead of using a CancellationToken and TokenSource I used a bool. My code ended up looking roughly like this:
private void AddSearchToDropDown ()
{
Task.Factory.StartNew (() =>
{
if (CanAdd && filterTxtBox.Text.Length > 2)
{
CanAdd = false;
Thread.Sleep (4000);
this.Invoke(new Action(() =>
{
filterTxtBox.AutoCompleteMode = AutoCompleteMode.None;
m_suggestedTests.Add (filterTxtBox.Text);
filterTxtBox.AutoCompleteMode = AutoCompleteMode.Suggest;
CanAdd = true;
}));
}
});
}
You'll also want code in your textChanged event handler that will set the bool to false whenever they begin typing in the textbox. That way you don't add the first entry 4 seconds after the first text changed event.
Second thing to be aware of is that there was a Violation Exception if I used AutoCompleteMode.SuggestAppend or Append.
While this isn't a complete answer I hope that it helps anyone that manages to find this question.

Find if TextBox.Text got changed by the user or by the code (Windows Phone 8)

I have a Windows Phone 8 project that converts values (i.e.: Celsius to Fahrenheit). There are two TextBox UI elements, one of which is read-only. The user can change the first TextBox to input the value to be converted. He can also press a button to "swap" the two TextBoxes so that he can do the reverse conversion. When the user presses the button, the value from the second TextBox goes into the first TextBox (and vice versa). But it's not the user who changed the value, it's the code who did.
I asked around (on IRC) and researched the subject, but I am a beginner and couldn't understand most of what I have found.
I heard that a simple solution would be to use Data Bindings. I researched the subject, and from what I read, Data Bindings can't solve my problem (correct me if I'm wrong).
I also tried to create a subclass of TextBox, hoping that I could hook in some custom event to it and go further in that direction. But I did not understand how to link the custom TextBox to the UI (in XAML). The way I created the subclass is to just create a new class and add TextBox as the parent. I know there is a template in VS to create a new User Control, and I tried it, but I couldn't understand what I was doing (or what I was supposed to do).
So I have two questions: Am I looking at the problem from the right angle? If yes, how do I create a custom TextBox and link it to the UI? If not, how could I solve my problem?
If your question is how to distinguish if the text got changed by the user or by the code then its simple.
Assuming that when the user types something you'd like to perform method A but when the code changes the text you'd like to perform method B:
In both cases you will need to override the TextBox.TextChanged() event handler.
You will also need a flag variable to tell you if the swap button was pressed or not.
The event handler should be something like this:
{
if (swap_pushed)
{
Method_B();
swap_pushed = false;
}
else
{
Method_A();
}
}
And finally your event handler for swap Button.Click() should be like this:
{
swap_pushed = true;
}

How to use 0x08

How do you use the ASCII value of backspace 0x08 programmatically in a WinForms TextArea? I tried in a console program:
Console.WriteLine("Hello" + (char)0x8 + "World");
And it shows as I expected:
HellWorld
Where as I tried in a WinForms TextArea to fill the value:
txt.Text += "Hello" + (char)0x8 + "World";
It shows like this:
What to make backspace event to trigger other than using Keyboard's event to make the display as I expect by using the value of 0x8 alone not accessing with any text field events. Through programmatically to print "HellWorld" in text field.
Characters and keypress are not related directly. You would have to get a Backspace keypress into the textbox in order to erase a character.
If you want to simulate someone typing in the textbox, then you might do so using SendKeys.Send(), e.g:
txt.Select();
SendKeys.Send("hello");
SendKeys.Send(((char)0x8).ToString()); // send backspace using 0x08
SendKeys.Send("{BS}"); // send backspace using predefined code
SendKeys.Send("world");
But pre-processing the strings seems much simpler (and safer), e.g:
var str = "hello";
txt.Text += str.Substring(0, str.Length-1);
Note: SendKeys.Send sends keystrokes to the active window. So if another window gets the focus while the above code is running, then the keystrokes might end in a different window.
The backspace character was introduced for thin clients that send input to a server character by character, to allow end users to fix a typo that was already sent. Modern applications usually have no use for such a character, as client applications now usually just wait until the user has finished entering data before sending it to the server.
That is why the TextBox control does not have support for it, and probably why people are wondering why you need this.
Anyway, you'll need to pre-process the data yourself before setting the TextBox's Text. You could for instance use regular expressions to simulate this behavior.

Categories