I have a Xamarin.Forms entry with numeric keyboard that will represent a pt-BR REAL currency (999.999,99). When I type numbers in the numeric keyboard, the comma(representing decimal) and dot(representind thousand) needs to be added automatically while I am typing.
To achieve this goal, what is the best practice/design pattern in Xamarin.Forms to work in all platforms?
The trick is to use a TextChanged event. The first step I removed the $ from the string so that I could parse the new text value. If it fails to parse, that means that the user added a non-digit character and we just revert to whatever the old text was.
Next, we detect if user ADDED a new digit and its to the RIGHT of the decimal (example 1.532). If so we, we move the decimal to the right by * 10. Do the opposite for a DELETION.
OH, and almost forgot about when we initialize the number! The first digit we enter will be a whole number so we * 100 to make sure the first digit we enter starts as fraction.
Once we got our decimal correct, we display it using num.ToString("C");
xaml:
<Entry
Keyboard="Numeric"
TextChanged="OnFinancialTextChanged"
Placeholder="$10.00"
Text="{Binding RetailPrice}"/>
Then in the cs
.cs:
private void OnFinancialTextChanged(object sender, TextChangedEventArgs e)
{
var entry = (Entry)sender;
var amt = e.NewTextValue.Replace("$", "");
if (decimal.TryParse(amt, out decimal num))
{
// Init our number
if(string.IsNullOrEmpty(e.OldTextValue))
{
num = num / 100;
}
// Shift decimal to right if added a decimal digit
else if (num.DecimalDigits() > 2 && !e.IsDeletion())
{
num = num * 10;
}
// Shift decimal to left if deleted a decimal digit
else if(num.DecimalDigits() < 2 && e.IsDeletion())
{
num = num / 10;
}
entry.Text = num.ToString("C");
}
else
{
entry.Text = e.OldTextValue;
}
}
I created these Extension methods to help with the logic
public static class ExtensionMethods
{
public static int DecimalDigits(this decimal n)
{
return n.ToString(System.Globalization.CultureInfo.InvariantCulture)
.SkipWhile(c => c != '.')
.Skip(1)
.Count();
}
public static bool IsDeletion(this TextChangedEventArgs e)
{
return !string.IsNullOrEmpty(e.OldTextValue) && e.OldTextValue.Length > e.NewTextValue.Length;
}
}