I am using below Property example to make some calculation on textbox and if textbox is null I am assigning zero to it so calculation won't fail as you can see I am using Math.Round and I want to make several checks on these textbox input like
textbox that only accepts numbers I searched and found method 1
I want my textbox to be formated I searched and found Method 2
Now my question is ..
Is there any way to mareg all these method in the property method I am using
so my code won't be like "spaghetti code" ?
is there any better ways to do these checks ?
Thank you in advance
Property example
public double ItemPriceResult
{
get
{
return Math.Round(ItemCost * RevenuePercentage / 100 + ItemCost, 0);
}
}
Method 1
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (System.Text.RegularExpressions.Regex.IsMatch(textBox1.Text, "[^0-9]"))
{
MessageBox.Show("Please enter only numbers.");
textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
}
}
Method 2
textBox1.Text = string.Format(System.Globalization.CultureInfo.GetCultureInfo("id-ID"), "{0:#,##0.00}", double.Parse(textBox1.Text));
UPDATE after some answers
MaskedTextBox seems fit my needs I read and searched and below some question
if you kindly would like to help me
I need to use MaskedTextBox because I can set it to accept
number and I can also force number formating so
also I need to make number textboxs easer to read for users
so 1000 will be come 1,000
and 10000 will be come 10,000
then according to Microsoft Docs formating MaskedTextBox to fit my needs
Masked MaskedTextBox with 999,999,999,
second I do not want the PromptCharto be visible I google it but none of search result did it
Try this , it will accept only numbers and u can format the string as u want using regex.
public static string ToMaskedString(this String value)
{
var pattern = "^(/d{2})(/d{3})(/d*)$";
var regExp = new Regex(pattern);
return regExp.Replace(value, "$1-$2-$3");
}
You have a TextBox. Alas you don't tell what kind of TextBox you use. System.Windows.Forms.TextBox? System.Web.UI.MobileControls.TextBox?
You write "if text box is null I am assigning zero to it". I assume that you mean that if no text is entered in the text box you assume that 0 is entered.
Furthermore you want to format the output of the text box whenever the text is changed. So while the operator is typing text you want to change this text? For the operator this is very annoying.
Wouldn't you prefer that the operator is obliged to type his text in the format you desire, helping him visually. For this you may use the class MaskedTextBox
The MaskedTextBox has a property Mask, which forces the operator to type in a certain format. I'm not really familiar with what you do with the format {0:#,##0.00}, but I assume you want the output double in a real format with two digits after the decimal point using the decimal point and the thousand separator as common in the current culture.
via the designer put in initialize component:
this.maskedTextBox1.Mask = "99990.00";
after adding the event for text changed:
private void maskedtextBox1_TextChanged(object sender, EventArgs e)
{
double enteredValue = 0.0; // value to use when empty text box
if (!String.IsNullOrEmpty(this.maskedtextBox1.Text))
{
enteredValue = double.Parse(maskedTextBox1.Text, myFormatProvider)
}
ProcessEnteredValue(enteredValue);
}
}
After your edit, the specifications have changed.
While entering the number in the text box, the operator should not have any visual feedback of the formatting of his number.
The operator is free to enter the real number in any commonly used format.
The value of the text box should not be used while the operator is editing the text box.
Only after editing is finished, the value of the text box should be interpreted for correctness, and if correct it should be used.
The actually used value should be displayed in the text box in a defined format.
The desire not to show any visual feedback while entering is understandable. After all, the program doesn't care whether the operator types 1000, 1000.00, or even 1.0E3.
The MaskedTextBox is especially used to force the operator to enter his number in a given format. Since this is not desired, my advise would be to use a TextBox instead of aMaskedTextBox.
However, because you give the operator the freedom to enter his number in any way he wants, including copy-paste, repairing typing errors, etc. you'll have to add the possibility for the user to express to the program that he has finished entering the number.
An often used method in the windows UI would be a Button. Another possibility would be the enter button. Be aware though that this is not really standard within windows. It might make learning your program a little bit more difficult.
So after the operator notified that he finished editing and the corresponding event function is called, your code could be:
// Get the numberformat to use, use current culture, or your own format
private readonly IFormatProvider myNumberFormat = CultureInfo.CurrentCulture.NumberFormat
private void OperatorFinishedEditing(TextBox box)
{
// read the text and try to parse it to a double
// accepting all common formats of real numbers in the current culture
bool valueOk = true;
double resultValue = 0;
if (!String.IsNullOrEmpty(box.Text))
{
bool valueOk = Double.TryParse(box.Text, out resultValue);
}
if (valueOk)
{
box.Text = FormatResultValue(resultValue);
ProcessValue(resultValue);
}
else
{
ShowInputProblem();
}
}
Related
I would really appreciate your help.
I have a DataGridView where user will be giving us double (2,43 etc).
I want to write a function which can detect if user puts dot in place of comma and just change it itself or treat it as comma for the calculations.
If it was a console app I would just simply write something like
public void ChangeToComma()
{
var someUserInput;
char arr[] = someUserInput.ToCharArray();
for (int i = 0, i < someUserInput.Length; i++)
{
if (char[i] == ".")
{
char[i] = ",";
}
}
}
That would be the logic I would use (maybe not correct but I just wanted to show better what I want to do).
I'm just starting with other than console apps so I'm stuck here :/
What I don't even have a slightest idea about (how to do it) is:
How to go through every single char in a specified DataGridView cell?
How to avoid changing every single dot in every cell of this DataGridView? Some of them are with text so they might contain dots.
You can do it by replacing the comma for a dot using the replace method contained in system
double value = double.Parse(dataGridViewTest.Rows[4].Cells[2].Value.ToString());
dataGridViewTest
.Rows[4]
.Cells[2].Value = value.ToString("N2");
"N2" as a parameter for method to string will set the value as decimal with two digits at the end.
You can also validate the input before saving the data to avoid users insert wrong the information in a wrong format.
I'm trying to format some doubles properly so that they will display properly for my uses (I'm building a statement in Devexpress, so I'm working with a lot of numbers).
Here are the basic formatting rules I'd like to have happen:
1000.2 -> 1,000.20
1000 -> 1,000
1000.22 -> 1,000.22
Is this possible using string formatting in C#? I've tried the following, but not been able to achieve my goal:
#,#.## - gives me 1,000.2 for the first value
#,#.#0 - gives me 1,000.00 for the second value
#,#.00 - gives me 1,000.00 for the second value
EDIT: Some more information. DevExpress gives me the ability to use string formatting to set up the values after they've been bound to the report. We're doing it at report time (and not at calculation time in the behind the scenes code) because we use the Sum function within the tables that DevExpress offers us. The reason we do THAT is so that we can minimize calls to our database by doing one large pull of data, then using that table over and over again in the statement and filtering based on the restrictions within.
EDIT EDIT:
Based on the feedback I've receieved here in the comments, it's not possible to perform the formatting I'd like to do with only providing a string format; I would need to insert some code either when I provide the data to the report (and then remove any and all formatting from the report) and perform all summing functions at the code level (to ensure that the sum values have the expected decimal places), or I would need to accept .00 at the end of, for example, some amount of yen (100 JPY would never be represented as 100.00 JPY, as an example).
This is a bit of an esoteric case, but it's good to know!
You can use string formatting coupled to a simple if condition. To shorten it's use, you can also make it an Extension method. It can look like this :
public static string FormatConditionnaly(this double input)
{
return input % 1 == 0 ? input.ToString("#,0") : input.ToString("#,0.00");
}
Basically, if you number does not contain any decimals (the % 1 == 0 check), you format it without decimals. If it fails the check, you add the two zeroes.
It is used like that :
const double flatNumber = 1000;
string result1 = flatNumber.FormatConditionnaly(); //1,000
const double numberWithDecimals = 1000.5;
string result2 = numberWithDecimals.FormatConditionnaly(); //1,000,50
Bit of a hack but you can give this a try:
s = String.Format("{0:N2}", 1000).Replace(".00", "");
Use the "N" format specifier as the format string when you call ToString(); See here
For example:
int intValue = 123456789;
Console.WriteLine(intValue.ToString("N2",
CultureInfo.InvariantCulture).Replace(".00", "");
You can customize group sizes etc. as needed.
Why don't you format the values before binding to DevExpress control using plain old C# (Assuming you are doing a bind, as you have not given sufficient details.)
In c# the Math.Round() should do the trick.
Example Math.Round(doubleValue,2) where the second parameter is the number of decimal places.
EDIT:
#,##0.00
I Do not have DevExpress controls to test my solution but I did find http://documentation.devexpress.com/#windowsforms/CustomDocument1498 online (not sure if you see it already).
It seems you can use the Number or Currency masks.
Also take a look at the Zero Placeholder under the custom section. based on the description, '0' is filled where the user has not supplied a value.
example: 123.4 --> 123.40
If the string that you're trying to format is in an XRTableCell of an XtraReport instance, you can handle the BeforePrint event on that cell to format its text. This event is triggered anytime that the report is rendered. Call GetCurrentColumnValue to retrieve the value that you want to format, use any of the code methods from the previous answers that will work for you, and then set that cell's text with your formatted string. Using #dweeberly's answer:
private void OnBeforePrint(object sender, PrintEventArgs e)
{
object value = this.GetCurrentColumnValue("YourField");
if (value != null)
{
yourCell.Text = String.Format("{0:N2}", value.ToString()).Replace(".00", "");
}
}
Based on the feedback I've receieved here in the comments, it's not possible to perform the formatting I'd like to do with only providing a string format; I would need to insert some code either when I provide the data to the report (and then remove any and all formatting from the report) and perform all summing functions at the code level (to ensure that the sum values have the expected decimal places), or I would need to accept .00 at the end of, for example, some amount of yen (100 JPY would never be represented as 100.00 JPY, as an example).
This is a bit of an esoteric case, but it's good to know!
I need to use basic functionality of the MaskedTextBox. I can get use of the 5 digit mask but there are few things that I want to change. Right now the box is looking like this:
and there are two thing I don't like. First - the Prompt char which is undersoce _. I deleted the field value in order to leave it empty (as I would like it to appear) but this gives an error - The property value is invalid. So is there a way to get rid of these underscores? And second - I use this value for one of my entity properties which is of integer type so I make a convertion :
if (txtNumOfAreas.Text != "")
{
string temp = txtNumOfAreas.Text;
bool result = Int32.TryParse(temp, out convertValue);
if (result)
{
entity.AreasCnt = convertValue;
}
else
{
MessageBox.Show(Resources.ERROR_SAVE, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
else
{
entity.AreasCnt = null;
}
which works fine unless someone decides to make experiments and insert something like _1__5_ then the conversion fails, but at first place I would like to make possible to write the digits only one after another. So is this possible too?
It looks like your MaskedEdit is more trouble than it's worth to deal with your particular range of issues. A better control to use might be the NumericUpDown.
The upside to NumericUpDown:
There are no underscore prompts to try and get rid of
It will only accept numeric input
So there is no need to try and convert the value. You will always have an integer
Setting Minimum and Maximum value properties gives you automatic data entry validation
Provides multiple modes of data entry:
Typing
Clicking up/down buttons with a mouse
Up/down with keyboard
If you like, you could hide the up/down buttons altogether: C# WinForms numericUpDown control (removing the spin box)
So to get the _ to be a space you just need to set the mask character to a single space. And to resolve the conversion error, just set the AllowPromptAsInput property to false so that the user can't actually end up with something like your example.
Right now, to accomodate the use of commas as decimal placeholders in languages like Danish, I retrieve values stored with decimal points, e.g. ".123" from a .resx file like this:
// Getting a value from a .resx parameter
double minValue = Convert.ToDouble(AppParams.minVal, CultureInfo.InvariantCulture);
And when I need to work with a value received from a TextBox, e.g. ",321" I use this:
// Getting a value from a TextBox
double newValue = Convert.ToDouble(value, CultureInfo.CurrentCulture);
In the .csproj file, I've added <SupportedCultures>da;</SupportedCultures> but otherwise haven't attempted some application-wide way of dealing with these two issues, other than what's shown.
You don't need to store the value as a string in resx file:
<data name="minVal" type="System.Double, mscorlib">
<value>.123</value>
</data>
This way the generated minVal property will be of type double, and you won't have to convert it manually.
The only issue with this approach is that you have to edit the resx file manually in XML, since the resource designer can't handle resources of this type (actually you can rename or remove a resource or change its value, but you can't change its type and you can't create a new one). Anyway, I've switched to manual editing of resx file since I started using Resharper, because it provides some nice analysis and refactoring features for these files ;)
As a side note, I don't think this minValue constant is a good candidate for resources. If it's a setting that can be changed, put it in settings, not in resources. If it's really a constant, make it a const in C# code. The only good reason to put it in resources is if you want the value to be localizable, and it doesn't seem likely in this case.
When you parse the string from the user input try to accept many possible inputs e.g.
public static class Helper
{
public static bool TryParseDouble(this TextBox textbox, out double value)
{
if (double.TryParse(textbox.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
{
textbox.Foreground = Brushes.Black; //indicates that the user typed correct number
return true;
}
else
{
textbox.Foreground = Brushes.Red; // not a number
return false;
}
}
}
When you parse .resx, XML and other files use also InvariantCulture. Here is a problem that I've encountered with XML parser.
When showing data to the user use the current culture.
I much appreciate the answers from Thomas Levesque and lukas. They contained some useful insight and examples. I'm posting this as an answer because I want to provide more info and an example solution. As with many computing/UI problems, compromises often have to be made. I made the unfortunate discovery that none of the InputScopeNameValues (MSDN InputScopeNameValue Enumeration) switch between decimal (.) and comma (,) when changing region+language settings (and, yes, I double-checked that the keyboard was set on my phone to only use Deutsch).
However, because these TextBox inputs are numeric and need to entered quickly, the numeric InputScopes are still the best way to go. Interestingly, even if the user is forced to use the decimal point in place of a comma, as soon as it's entered in the TextBox the string format changes, e.g. from ".123" to ",123" even though as shown"{0:#.000}". Thus the compromise and in the code below, the workaround (tested so far in en-US and de-DE).
Note: As lukas mentioned, it is always wise to validate user input. I'm not using TryParse here (although I may) so I don't have to rewrite a lot of code. This is mitigated in the UI by choosing a numeric InputScope and in the handling code via try/catch blocks, which even handle correctly a user attempting to bypass the numeric input by pasting text from the clipboard:
<TextBox x:Name="myTBox" InputScope="Number" Text="{Binding SomeNumber, Mode=TwoWay}" />
And code:
public string SomeNumber
{
get
{
return String.Format("{0:#.000}", SomeProfileModel.Instance.SomeProfile.SomeNumber);
}
set
{
if (SomeProfileModel.Instance.SomeProfile.SomeNumber.ToString() == value) return;
var oldValue = SomeProfileModel.Instance.SomeProfile.SomeNumber;
try
{
double newValue;
try
{
newValue = Convert.ToDouble(value, CultureInfo.CurrentCulture);
}
catch (Exception)
{
newValue = Convert.ToDouble(value, CultureInfo.InvariantCulture);
}
if (Convert.ToDouble(MyAppParams.SomeNumberMin, CultureInfo.InvariantCulture) > newValue || Convert.ToDouble(MyAppParams.SomeNumberMax, CultureInfo.InvariantCulture) < newValue)
{
// Revert back to previous value
// NOTE: This has to be done here. If done in the catch statement,
// it will never run since the MessageBox interferes with it.
throw new Exception();
}
SomeProfileModel.Instance.SomeProfile.SomeNumber = newValue;
RaisePropertyChanged("SomeNumber", oldValue, newValue, true);
}
catch (Exception err)
{
System.Windows.MessageBox.Show("Value must be a number between " + MyAppParams.SomeNumberMin + " and " + MyAppParams.SomeNumberMax);
}
}
}
This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
How to handle when the backspace button is pressed and the input panel has digit grouped numbers. E.g. 434,343,334.232.
Basically the question says it all, I'm making a calculator in c# and I'm stuck on this problem. When digit grouping is hit the numbers get separated by commas, when the user hits the backspace button, the commas act like characters that get deleted.
inputPanelTextBox.Text = inputPanelTextBox.Text.Replace(",", "") I put this piece of code under my backspace click event. The problem is that say the panel has 234,232 and the user presses the backspace button, the comma is gone as well as the 2 on the far right.
What I want to happen is the same way the windows 7 calculator does when the digit grouped menu is checked and the user hits the backspace.
Any idea of how to go about this? Thank you so much in advance.
How about you store the number just as a number then format the number to look nice when you output it. The same thing will work with string.Format(). You could reformat the number into the display string every time the user hits backspace or adds a new digit. There are lots of the string format modifiers listed here.
int numWithComma = 3000;
int numWithoutComma = 50;
Console.WriteLine("numWithComma: {0:n}", numWithComma);
Console.WriteLine("numWithoutComma: {0:n}", numWithoutComma);
// prints:
// numWithComma: 3,000.00
// numWithoutComma: 50.00
If I were making this calculator, I would save the number in a double, then when the number needs to be displayed I would run it through a function like this and display the string to the user:
private static string FormatForDisplay(double number)
{
return string.Format("{0:n}", number);
}
How about using a format string when you output the number, that way you don't have to manage commas at all.
double myDouble = 500000.012345
inputPanelTextBox.Text = myDouble.ToString("N", CultureInfo.InvariantCulture);
Its been a while since I've used Visual Studio but I'm pretty sure you can set these format strings directly on text boxes so its simply automatically handled when they type. And its easy as pie to set in the properties if I remember correctly. Check out Standard Numeric Format Strings for a bit more on it.
Also a MaskedTextBox might work as well, set the mask to something like "999,999,999,999.99" and see how that formats different numbers.
Good Luck! :D