On my form I have 3 entry
controls. I'm trying to validate the 'Age' control, with the following validation rules:
Cannot enter more than 3 digits
Cannot enter a decimal place (.)
Cannot enter a hyphen (-)
To do this, I've set the 'TextChanged' property of my control to be
TextChanged="OnAgeTextChanged"
My OnAgeTextChanged
method is:
private void OnAgeTextChanged(object sender, TextChangedEventArgs e)
{
var entry = (Entry)sender;
try
{
if (entry.Text.Length > 3)
{
string entryText = entry.Text;
entry.TextChanged -= OnAgeTextChanged;
entry.Text = e.OldTextValue;
entry.TextChanged += OnAgeTextChanged;
}
string strName = entry.Text;
if (strName.Contains(".") || strName.Contains("-"))
{
strName = strName.Replace(".", "").Replace("-", "");
entry.Text = strName;
}
}
catch(Exception ex)
{
Console.WriteLine("Exception caught: {0}", ex);
}
}
However, when the if conditions are met, the event is being looped over multiple times, causing the application to run slowly.
For example, if I enter my age as 1234, it loops over the code multiple times so there's a delay, with the delay increasing each time the text gets changed.
What other way can I achieve this validation, but without the event being called multiple times?
EDIT
After updating the code to remove the TextChanged
trigger on my control before re-assigning it at the end of the method, it still loops over multiple times, and the number of loops increases with each key press.
Entry control xaml
<Entry x:Name="txtAge"
Placeholder="Age"
Keyboard="Numeric"
TextColor="DarkBlue"
PlaceholderColor="DarkBlue"
Completed="AgeCompleted"
HorizontalOptions="Start"
WidthRequest="55"
TextChanged="OnAgeTextChanged"
/>
TextChanged
event
private void OnAgeTextChanged(object sender, TextChangedEventArgs e)
{
var entry = (Entry)sender;
try
{
entry.TextChanged -= OnAgeTextChanged;
if (entry.Text.Length > 3)
{
entry.Text = e.OldTextValue;
}
string strName = entry.Text;
if (strName.Contains(".") || strName.Contains("-"))
{
strName = strName.Replace(".", "").Replace("-", "");
entry.Text = strName;
}
}
catch(Exception ex)
{
Console.WriteLine("Exception caught: {0}", ex);
}
finally
{
entry.TextChanged += OnAgeTextChanged;
}
}
The way that I resolved this issue in the end was using a separate class to handle my validations.
My validation class:
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class viewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string age_;
public string Age { get { return age_; } set { if (age_ != value) { age_ = ProcessAge(value); OnPropertyChanged(); } } }
private string ProcessAge(string age)
{
if (string.IsNullOrEmpty(age))
return age;
if (age.Length > 3)
age = age.Substring(0, 3);
if (age.StartsWith("0"))
age = age.Remove(0, 1);
return age.Replace(".", "").Replace("-", "");
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then, I can bind the form to use this class, with:
public MainPage()
{
InitializeComponent();
BindingContext = new viewModel();
}
And finally, to bind the entry control to use the Age property, I set the Text
property
Text="{Binding Age, Mode=TwoWay}"
What this now does, is every time the value in the Age control changes, it will look to the Age property in the new class and see that to set it, it needs to go through ProcessAge
to validate it, and this is where the checks are now done.
This is faster, as it only occurs once per key press and there's no fiddling around required with subscribing and unsubscribing the TextChanged
event and no loops.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With