Xamarin入口控制TextChanged事件循环
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Xamarin入口控制TextChanged事件循环相关的知识,希望对你有一定的参考价值。
在我的表格上我有3个entry
控件。我正在尝试使用以下验证规则验证“年龄”控件:
- 不能输入超过3位数
- 无法输入小数位(。)
- 无法输入连字符( - )
为此,我将控件的'TextChanged'属性设置为
TextChanged="OnAgeTextChanged"
我的OnAgeTextChanged
方法是:
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);
}
}
但是,当满足if条件时,事件将多次循环,导致应用程序运行缓慢。
例如,如果我输入我的年龄为1234,它会多次循环代码,因此会有延迟,每次文本更改时延迟都会增加。
我可以通过其他方式实现此验证,但不会多次调用该事件?
编辑
更新代码以删除控件上的TextChanged
触发器,然后在方法结束时重新分配它时,它仍会循环多次,并且每次按键时循环次数都会增加。
入境管制xaml
<Entry x:Name="txtAge"
Placeholder="Age"
Keyboard="Numeric"
TextColor="DarkBlue"
PlaceholderColor="DarkBlue"
Completed="AgeCompleted"
HorizontalOptions="Start"
WidthRequest="55"
TextChanged="OnAgeTextChanged"
/>
TextChanged
事件
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;
}
}
看起来你从事件中得到的object sender
不是你的Entry
生成的XAML
的完全相同的例子。
那么,这可以解释这个问题:
entry.TextChanged -= OnTextChanged;
对你的代码没有任何影响,这个对象还没有订阅者
然后,在你的东西结束时,你设置:
entry.TextChanged += OnAgeTextChanged;
现在确实如此。你是'永生化'这个例子(sender
)。
我想知道它是否是一种优雅的方式来解决你的具体问题(后来我会尝试发布一些替代方案,如果它有效)但为了使其有效,我猜你可以尝试取消订阅并再次订阅txtAge
对象引用:
private void OnAgeTextChanged(object sender, TextChangedEventArgs e)
{
try
{
txtAge.TextChanged -= OnAgeTextChanged;
if (e.NewTextValue?.Length > 3 ?? false)
txtAge.Text = e.OldTextValue;
string strNumber = txtAge.Text;
if (strNumber.Contains(".") || strNumber.Contains("-"))
{
strNumber = strNumber.Replace(".", "").Replace("-", "");
txtAge.Text = strNumber;
}
}
catch(Exception ex)
{
Console.WriteLine("Exception caught: {0}", ex);
}
finally
{
txtAge.TextChanged += OnAgeTextChanged;
}
}
我希望它有所帮助。
我最终解决这个问题的方法是使用一个单独的类来处理我的验证。
我的验证课:
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));
}
}
然后,我可以绑定表单来使用这个类,用:
public MainPage()
{
InitializeComponent();
BindingContext = new viewModel();
}
最后,为了绑定入口控件以使用Age属性,我设置了Text
属性
Text="{Binding Age, Mode=TwoWay}"
现在这样做,是每次Age控件中的值发生变化时,它会查看新类中的Age属性并看到要设置它,它需要通过ProcessAge
来验证它,这就是检查的地方现在已经完成了。
这个速度更快,因为它只在每次按键时出现一次,并且订阅和取消订阅TextChanged
事件并且没有循环时不需要摆弄。
最好使用条目无焦点事件,这样它就不会对事件处理程序进行如此多的调用,因此性能会得到提高!
这应该可以解决您的问题:
private void OnAgeTextChanged(object sender, TextChangedEventArgs e)
{
var entry = (Entry)sender;
entry.TextChanged -= OnAgeTextChanged;
try
{ //[...] Your stuff
}
catch(Exception ex)
{
//[...] Your other stuff
}
finally{
entry.TextChanged += OnAgeTextChanged;
}
}
因为在下面的代码中,您在事件处理程序仍在侦听时更改文本,因此将至少再次触发一次。
if (strName.Contains(".") || strName.Contains("-"))
{
strName = strName.Replace(".", "").Replace("-", "");
entry.Text = strName;
}
以上是关于Xamarin入口控制TextChanged事件循环的主要内容,如果未能解决你的问题,请参考以下文章