Auto Complete formatting for TextBox? - c#

I have been looking for a way to have a TextBox format while the user is inputting data.
I have made a hack that does what I want, but it is a bit finicky due things like when you accidentally press two keys at once which can screw with the if statements and when trying to delete the string via Delete Key by the user.
Anyway, that is not the issue and this is the code that I am using now:
Calling the methods from this class, The first method adds commas to the string and the second method checks if a comma is at the end when the user has finnished typing.
class BonusData
{
public class DoDataTextBox
{
public static void AutoComplete(TextBox textBox, int counter)
{
if (textBox.Text.Length - counter == 3)
{
textBox.Text = textBox.Text + ",";
textBox.SelectionStart = textBox.Text.Length;
}
else if (textBox.Text.Length - counter == 7)
{
textBox.Text = textBox.Text + ",";
textBox.SelectionStart = textBox.Text.Length;
}
else if (textBox.Text.Length - counter == 11)
{
textBox.Text = textBox.Text + ",";
textBox.SelectionStart = textBox.Text.Length;
}
}
public static void CheckLastCharacter(TextBox textBox)
{
if (textBox.Text.Length < 2) return;
if (textBox.Text.Substring(textBox.Text.Length - 1) != ",") return;
{
textBox.Text = textBox.Text.Substring(0, textBox.Text.Length - 1);
}
}
}
}
And the event handlers,
private void SecondMonthRowOne_OnKeyUp(object sender, KeyEventArgs e)
{
int counter = 0;
if (IsText)
{
counter = 1;
}
BonusData.DoDataTextBox.AutoComplete((TextBox)sender, counter);
}
private void SecondMonthRowOne_OnGotFocus(object sender, RoutedEventArgs e)
{
if (e.ToString() != String.Empty) return;
IsText = true;
}
private void SecondMonthRowOne_OnLostFocus(object sender, RoutedEventArgs e)
{
BonusData.DoDataTextBox.CheckLastCharacter((TextBox)sender);
IsText = false;
}
Which gives a result like this,
999,999,999
Like I said it works 98% of the time, but I was hoping there was another way to do this in WPF. I have searched far and wide, but I don't even know what something like this is called.

I suggest you to use "WPF TextBox AutoComplete" instead. It's a WPF attached behavior wrapped in a NuGet package.
You can simply add this package to your project by adding this using NuGet Package Manager for your WPF project.
This NuGet package is also open source, therefore you can customize it further to meet your needs/requirements.
The source code is hosted on this GitHub repo: https://github.com/Nimgoble/WPFTextBoxAutoComplete
NOTE: I haven't fully tested this WPF library against .NET 4.6. The library is compiled against .NET 4.5 as its target. But as far as I know, it's 100% compatible with WPF in .NET 4.6.

Without using any outside addins I found this to work really well,
This will add a Comma every third character and allow users to delete characters one at a time.
The TextBox format will look like this,
999,999,999,999
The code,
public class DoDataTextBox
{
public static void AutoCompleteStringBuild(TextBox textBox)
{
string endResult = null;
string replace = Reverse(textBox.Text).Replace(",", "");
int count = 1;
char[] value = replace.ToCharArray();
foreach (var car in value)
{
if (count % 3 == 0)
{
endResult = String.Concat(endResult, car);
if (value.Length != count)
{
endResult = String.Concat(endResult, ",");
}
count++;
}
else
{
endResult = String.Concat(endResult, car);
count++;
}
}
if (endResult == null) return;
string textBoxResult = Reverse(endResult);
textBox.Text = textBoxResult;
}
public static string Reverse(string stringVal)
{
char[] charArray = stringVal.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
public static void IsDeleteKey(TextBox textBox, KeyEventArgs e)
{
textBox.SelectionStart = e.Key == Key.Delete ? 0 : textBox.Text.Length;
}
}
And the event handler,
private void TextBoxOne_OnKeyUp(object sender, KeyEventArgs e)
{
BonusData.DoDataTextBox.AutoCompleteStringBuild((TextBox)sender);
BonusData.DoDataTextBox.IsDeleteKey((TextBox)sender, e);
}
At present this is the best way I have found to do this.

Related

TextBox only allow enter certain range of numbers, but its not accept some correct value

Good evening,
trying to make WPF textbox accept only double value between 3 and 2813
in the code below ,I can't write any value start with 1 or 2
like 11,22,113,215,2008
private bool IsValid(string str)
{
double i;
return double.TryParse(str, out i) && i >= 3 && i <= 2813;
}
private void L_Text_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
e.Handled = !IsValid(((TextBox)sender).Text + e.Text);
}
PreviewTextInput occurs whenever the user presses a key. So we can't know whether the user intends to write "2" or "22" at this moment.
To evaluate the value we must be sure that the user finished writing. You can use LostFocus event for this purpose.
private bool IsValid(string str)
{
double i;
return double.TryParse(str, out i) && i >= 3 && i <= 2813;
}
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
var txt = sender as TextBox;
if (!IsValid((txt.Text)))
{
//invalid delete text
txt.Text = "";
}
}
Detailed validation: https://stackoverflow.com/a/37255232/1431001
There are 2 things you could do
You could evaluate if it starts with a specific character, and then parse that
You could use https://help.syncfusion.com/wpf/double-textbox/getting-started

Why does my backspace return a new text instead of updating the current text?

I am trying my hand at a self teaching project by creating a calculator. I am having trouble getting my backspace to update the text in my textbox. My goal is to be able to Backspace using my backspace button and add a number afterward and having my result being exactly whats expected with any backspace i.e.
(1) string of 701
(2) Backspace used
(3) Adding 4 to the string
(4) return 704
What I am thinking is that when I click the button it is returning a new string and when I enter a new number, it is updating the old string. I have tried this code in the btnBck_Click function as well as what I am showing in my current code(the BackSpaceFunction(); is my attempt to tell the program to return the updated string).
private void btnBck_Click(object sender, EventArgs e)
{
BackSpaceFunction();
}
private string BackSpaceFunction()
{
string textBoxText = textBox1.Text;
textBoxText = textBox1.Text.Remove(textBoxText.Length - 1);
if (textBox1.Text.Length >= 1)
{
textBox1.Text = textBox1.Text.Replace(textBox1.Text, textBoxText);
return textBox1.Text;
}
else if (textBox1.Text.Length == 0)
{
textBox1.Text = "0";
input = string.Empty;
operand1 = string.Empty;
operand2 = string.Empty;
}
return textBox1.Text;
}
(Please understand my excessive explaining and use of examples is to make sure everyone can understand in case I myself missed the point. Thank you in advance)
I am having trouble getting my backspace to update the text in my textbox
The TextBox control supports use of the backspace key directly. As long as the TextBox has the input focus, pressing the backspace key will delete the character just before the current insertion point.
Your code example is incomplete, but it looks like you have a separate Button object that is intended to provide similar functionality. You aren't taking into account the insertion point for the TextBox, so presumably you just always want to remove the last character. If that's the case, your method is far more complicated than it needs to be. You can just use string.Substring() to remove the last character:
private string BackSpaceFunction()
{
if (textBox1.Length > 0)
{
textBox1.Text = textBox1.Text.Substring(0, textBox1.Text.Length - 1);
}
if (textBox1.Text.Length == 0)
{
textBox1.Text = "0";
input = string.Empty;
operand1 = string.Empty;
operand2 = string.Empty;
}
return textBox1.Text;
}
(You never actually use the return value, so it's not clear why the method has a return value. But I left that in because it's not inherently a problem.)
So to answer my own question, I took the time to try and figure it out for myself. I ended up succeeding and found that this code worked (look at the "if" portion of my if statement).
private void btnBck_Click(object sender, EventArgs e)
{
BackSpaceFunction();
}
private string BackSpaceFunction()
{
//textBoxText = textBox1.Text.Remove(textBoxText.Length - 1);
if (textBox1.Text.Length >= 1)
{
string textBoxText = textBox1.Text.Remove(textBox1.Text.Length - 1);
string updatedText = textBox1.Text = textBox1.Text.Replace(textBox1.Text, textBoxText);
textBox1.Text = updatedText;
input = string.Format(textBox1.Text, updatedText);
operand1 = string.Format(textBox1.Text, updatedText);
operand1 = string.Format(textBox1.Text, updatedText);
}
else if (textBox1.Text.Length == 0)
{
textBox1.Text = "0";
input = string.Empty;
operand1 = string.Empty;
operand2 = string.Empty;
}
return textBox1.Text;
}'''
I'm not exactly sure why I had to use Format for input, operand1, and operand2 but it ended up doing exactly what I needed. If there are any explanations as to why this worked I will gladly accept the learning opportunity. :)

.net CF 3.5 Remove() or RemoveAt() crashes application

I'm using .net CF 3.5 to develop an application for Windows Mobile 5.0
I have a ListBox with a list of numbers in. When they click on a number in the list, it should be deleted from the list. I can get the selected item's index just fine from the list - However, I cannot seem to delete it without the application crashing. There are no errors, it will just exit with code 0.
private void DeleteOrder(object sender, EventArgs e) {
string s = (string) orders_list.SelectedItem;
int size = orders_list.Items.Count;
bool con = true;
for (int i = 0; i < size; i++) {
Debug.Write("\nIS: " + i + "\n");
if (con) {
if (s != null || s != "") {
if (orders_list.GetItemText(orders_list.Items[i]) != null) {
if (orders_list.GetItemText(orders_list.Items[i]).ToString() == s) {
if (orders_list.Items[i] != null) {
Debug.Write("ORDER IS : " + orders_list.Items[i].ToString());
orders_list.Items.Remove(orders_list.Items[i].ToString());
}
con = false;
}
}
}
}
}
input_scan.Text = "";
this.BackColor = Color.Lime;
input_scan.Focus();
}
}
}
As you can see, I've tried doing
orders_list.Items.Remove(orders_list.Items[i].ToString());
to see if I can remove the string object and I've tried using RemoveAt() to remove by index, but each time the application will keep crashing.
Any help would be appreciated as something so simple such as removing from a collection has become rather a challenge.

Adding a counter for the correct answer to determine the users score

I'm trying to add a counter that will determine the users score if the user inputs the correct answer. Though I can't seem to figure out how to add it into this if statement, or whether I need a new if statement.
This is the code to check the answer.
private void btnCheckAnswer_Click(object sender, EventArgs e)
{
string Answer = txtGuess.Text;
if (Answer.ToLower().Equals(country[index].ToLower()))
MessageBox.Show("Correct!");
else
MessageBox.Show("Incorrect!");
}
How would you add a counter that will be equivalent to the answer the user inputs. This counter will be displayed in a label called lblScoreCount.
Thank you for time, Ben
I suggest using properties, do not add lblScoreCount changing into if statement, but put it into property set.
private int m_Attempts = 0;
// You may want this as well
private int m_CorrectAnswers = 0;
private void ChangeScore() {
lblScoreCount.Text = String.Format("{0} right answers from {1} attempts",
CorrectAnswers, Attempts);
}
private int Attempts {
get {
return m_Attempts;
}
set {
m_Attempts = value;
ChangeScore();
}
}
// You may want this as well
private int CorrectAnswers {
get {
return m_CorrectAnswers;
}
set {
m_CorrectAnswers = value;
ChangeScore();
}
}
Properties can leave the main logic as simple as it's possible:
private void btnCheckAnswer_Click(object sender, EventArgs e) {
string Answer = txtGuess.Text;
Attempts += 1;
if (String.Equals(txtGuess.Text,
country[index],
StringComparison.OrdinalIgnoreCase)) {
CorrectAnswers += 1;
MessageBox.Show("Correct!");
}
else {
MessageBox.Show("Incorrect!");
}
}
You'll have to add curly braces to your if statement to allow multiple statements in the true case:
// counter somewhere in your module/class/form/...
int counter = 0;
// ...
if(Answer.ToLower() == country[index].ToLower()) {
MessageBox.Show("Correct!");
counter++;
} // ...

Find Next function in Windows Store App

I'm trying to make 'find/find next' function in my windows store application.
Word which I want to search and select is in textBox named 'tboxFind'.
Textbox 'EditorWindow' contains all my text.
My function works good only if there is one line of text in 'editorWindow'.
Otherwise, selection is moved forwards by number of new lines.
How to fix it?
Is there any simple way to create find next function?
private void btnFind_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
if ((tmpPos) == pos && tmpWord == tboxFind.Text && !String.IsNullOrEmpty(editorWindow.Text))
{
string tmpString = editorWindow.Text.Substring(pos + tboxFind.Text.Length);
tmpPos = tmpString.ToLower().IndexOf(tboxFind.Text.ToLower());
if (tmpPos != -1)
{
editorWindow.Focus(Windows.UI.Xaml.FocusState.Keyboard);
editorWindow.SelectionStart = pos + tmpPos + tboxFind.Text.Length;
editorWindow.SelectionLength = tboxFind.Text.Length;
pos = pos + tmpPos + tboxFind.Text.Length;
}
}
tmpWord = tboxFind.Text;
tmpPos = pos;
}
// EDIT:
I found a different way to create that function. Here is my code:
private void btnFind_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
numOfNewLines = 0;
pos = (tmpWord == tboxFind.Text) ? editorWindow.Text.ToLower().IndexOf(tboxFind.Text, pos + tboxFind.Text.Length)
: editorWindow.Text.ToLower().IndexOf(tboxFind.Text);
if (pos != -1)
{
foreach (char s in editorWindow.Text.Substring(0, pos))
{
if (s == '\n')
{
numOfNewLines++;
}
}
pos -= numOfNewLines;
editorWindow.Focus(Windows.UI.Xaml.FocusState.Keyboard);
//tmpPos = editorWindow.Text.ToLower().IndexOf(tboxFind.Text);
editorWindow.Select(pos, tboxFind.Text.Length);
pos += numOfNewLines;
}
tmpWord = tboxFind.Text;
}
I'm not 100% sure what's wrong with your code because I can't fully replicate it, but consider the following SSCCE in a basic Windows application:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
foreach (var i in FindIndicies("text"))
{
this.textBox1.SelectionStart = i;
this.textBox1.SelectionLength = "text".Length;
var result = MessageBox.Show(
"Move to the next index?",
"Next?",
MessageBoxButtons.YesNo);
if (result == System.Windows.Forms.DialogResult.No) { break; }
}
}
private List<int> FindIndicies(string textToFind)
{
var indicies = new List<int>();
var offset = 0;
var i = 0;
while ((i = this.textBox1.Text.IndexOf(
textToFind,
offset,
StringComparison.CurrentCultureIgnoreCase)) > 0)
{
indicies.Add(i);
offset = (i + textToFind.Length);
}
return indicies;
}
}
given that textBox1 has a set text value of:
Here is a set of text
and I'm going to find the word text
Even when there are multiple lines of text.
It finds each index properly, and selects them properly.
I would consider finding all indicies up front with the method I wrote and then simply iterate through them on demand. In my case I'm using a message box to determine when I want to move to the next index, but you'll use something different.

Categories