英文:
MAUI: custom behavior hangs
问题
我有这个自定义行为附加到一个Entry
字段:
public partial class SsnValidationBehavior : TextValidationBehavior
{
public static readonly BindableProperty Iso2CountryProperty = BindableProperty.Create(nameof(Iso2Country), typeof(string), typeof(SsnValidationBehavior), "cl");
public string Iso2Country
{
get => (string)GetValue(Iso2CountryProperty);
set => SetValue(Iso2CountryProperty, value);
}
public static bool ChileValidate(string docNumber)
{
string rut = CleanRegex().Replace(docNumber, string.Empty).ToUpper();
if (rut.Length >= 2)
{
string dv = rut[rut.Length - 1].ToString();
if (MatchRegex().IsMatch(dv))
{
int largo = rut.Length;
if (largo > 10 || largo < 2) return false;
// La parte del RUT debe ser un número entero
if (int.TryParse(rut.AsSpan(0, largo - 1), out _))
{
// El dígito verificador debe ser un número o la K
if ((rut[largo - 1].CompareTo('0') < 0 || rut[largo - 1].CompareTo('9') > 0) && rut[largo - 1] != 'K')
return false;
// Realiza la operación módulo
int suma = 0;
int mul = 2;
// -2 porque rut contiene el dígito verificador, el cual no hay que considerar
for (int i = rut.Length - 2; i >= 0; i--)
{
suma += int.Parse(rut[i].ToString()) * mul;
if (mul == 7) mul = 2; else mul++;
}
int residuo = suma % 11;
char dvr;
if (residuo == 1)
dvr = 'K';
else if (residuo == 0)
dvr = '0';
else
dvr = (11 - residuo).ToString()[0];
return dvr.Equals(rut[^1]);
}
}
}
return false;
}
protected override async ValueTask<bool> ValidateAsync(string value, CancellationToken token)
{
bool result = true;
string iso2 = Iso2Country ?? string.Empty;
switch (iso2)
{
case "cl":
result = ChileValidate(value);
break;
}
return result && await base.ValidateAsync(value, token);
}
[GeneratedRegex("[ .-]")]
private static partial Regex CleanRegex();
[GeneratedRegex("[0-9K]")]
private static partial Regex MatchRegex();
}
当我在字段中按任意键时,应用程序挂起(甚至是Visual Studio)。我在ValidateAsync
上放置了一个断点,但没有达到。
我从https://github.com/CommunityToolkit/Maui/blob/main/src/CommunityToolkit.Maui/Behaviors/Validators/EmailValidationBehavior.shared.cs
中获取了这个行为的模型。
有任何帮助吗?
英文:
I have this custom behavior attached to an Entry
field:
public partial class SsnValidationBehavior : TextValidationBehavior
{
public static readonly BindableProperty Iso2CountryProperty = BindableProperty.Create(nameof(Iso2Country), typeof(string), typeof(SsnValidationBehavior), "cl");
public string Iso2Country
{
get => (string)GetValue(Iso2CountryProperty);
set => SetValue(Iso2CountryProperty, value);
}
public static bool ChileValidate(string docNumber)
{
string rut = CleanRegex().Replace(docNumber, string.Empty).ToUpper();
if (rut.Length >= 2)
{
string dv = rut[rut.Length - 1].ToString();
if (MatchRegex().IsMatch(dv))
{
int largo = rut.Length;
if (largo > 10 || largo < 2) return false;
// La parte del RUT debe ser un número entero
if (int.TryParse(rut.AsSpan(0, largo - 1), out _))
{
// El dígito verificador debe ser un número o la K
if ((rut[largo - 1].CompareTo('0') < 0 || rut[largo - 1].CompareTo('9') > 0) && rut[largo - 1] != 'K')
return false;
// Realiza la operación módulo
int suma = 0;
int mul = 2;
// -2 porque rut contiene el dígito verificador, el cual no hay que considerar
for (int i = rut.Length - 2; i >= 0; i--)
{
suma += int.Parse(rut[i].ToString()) * mul;
if (mul == 7) mul = 2; else mul++;
}
int residuo = suma % 11;
char dvr;
if (residuo == 1)
dvr = 'K';
else if (residuo == 0)
dvr = '0';
else
dvr = (11 - residuo).ToString()[0];
return dvr.Equals(rut[^1]);
}
}
}
return false;
}
protected override async ValueTask<bool> ValidateAsync(string value, CancellationToken token)
{
bool result = true;
string iso2 = Iso2Country ?? string.Empty;
switch (iso2)
{
case "cl":
result = ChileValidate(value);
break;
}
return result && await base.ValidateAsync(value, token);
}
[GeneratedRegex("[ .-]")]
private static partial Regex CleanRegex();
[GeneratedRegex("[0-9K]")]
private static partial Regex MatchRegex();
}
When I press any key in the field, the app hangs (even Visual Studio). I placed a breakpoint at ValidateAsync
but it is not reached.
I took the model of this behavior from https://github.com/CommunityToolkit/Maui/blob/main/src/CommunityToolkit.Maui/Behaviors/Validators/EmailValidationBehavior.shared.cs
Any help?
答案1
得分: 1
首先,我已经创建了一个新的项目来测试您的自定义行为。但我无法重现您的问题。以下是代码:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp4.NewPage2"
xmlns:mybehavior="clr-namespace:MauiAppTest"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
Title="NewPage2">
<ContentPage.Resources>
<Style x:Key="InvalidEntryStyle" TargetType="Entry">
<Setter Property="TextColor" Value="Blue" />
</Style>
<Style x:Key="ValidEntryStyle" TargetType="Entry">
<Setter Property="TextColor" Value="Green" />
</Style>
</ContentPage.Resources>
<Entry x:Name="entry">
<Entry.Behaviors>
<mybehavior:SsnValidationBehavior
InvalidStyle="{StaticResource InvalidEntryStyle}"
ValidStyle="{StaticResource ValidEntryStyle}"
Flags="ValidateOnValueChanged"
MinimumLength="1"
MaximumLength="10" />
</Entry.Behaviors>
</Entry>
</ContentPage>
此外,我还添加了一个断点在ValidateAsync
方法,它可以被触发。首先,我看到iso2
和Iso2Country
的值始终是cl
(默认值),因此result && await base.ValidateAsync(value, token)
始终为false。看起来您从未调用过Iso2Country的setter方法。
另外,我也查看了您的最后一个问题。如果您想检查输入框的文本是否为null或为空,您可以使用DataTrigger来实现。例如:
<Entry x:Name="entry">
<Entry.Triggers>
<DataTrigger TargetType="Entry" Binding="{Binding Source={x:Reference entry}, Path=Text}" Value="{x:Null}">
<Setter Property="BackgroundColor" Value="Pink"/>
</DataTrigger>
<DataTrigger TargetType="Entry" Binding="{Binding Source={x:Reference entry}, Path=Text.Length}" Value="0">
<Setter Property="BackgroundColor" Value="Pink"/>
</DataTrigger>
</Entry.Triggers>
</Entry>
这将根据输入框的文本是否为null或长度是否为0来设置背景颜色为粉红色。
英文:
Frist of all, I have created a new project to test your custom behavior. But I can't reproduce your problem. There is the code:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp4.NewPage2"
xmlns:mybehavior="clr-namespace:MauiAppTest"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
Title="NewPage2">
<ContentPage.Resources>
<Style x:Key="InvalidEntryStyle" TargetType="Entry">
<Setter Property="TextColor" Value="Blue" />
</Style>
<Style x:Key="ValidEntryStyle" TargetType="Entry">
<Setter Property="TextColor" Value="Green" />
</Style>
</ContentPage.Resources>
<Entry x:Name="entry">
<Entry.Behaviors>
<mybehavior:SsnValidationBehavior
InvalidStyle="{StaticResource InvalidEntryStyle}"
ValidStyle="{StaticResource ValidEntryStyle}"
Flags="ValidateOnValueChanged"
MinimumLength="1"
MaximumLength="10" />
</Entry.Behaviors>
</Entry>
</ContentPage>
And I have added the break point at the ValidateAsync
and it can be hit. First, I saw the value of the iso2
and Iso2Country
always be cl
(default value), so the result && await base.ValidateAsync(value, token)
always be false. It seems you never called the Iso2Country's setter method.
In addition, I also check your last question. If you want to check the entry's text is null or empty. You can use the datatrigger to do that. Such as:
<Entry x:Name="entry">
<Entry.Triggers>
<DataTrigger TargetType="Entry" Binding="{Binding Source={x:Reference entry}, Path=Text}" Value="{x:Null}">
<Setter Property="BackgroundColor" Value="Pink"/>
</DataTrigger>
<DataTrigger TargetType="Entry" Binding="{Binding Source={x:Reference entry}, Path=Text.Length}" Value="0">
<Setter Property="BackgroundColor" Value="Pink"/>
</DataTrigger>
</Entry.Triggers>
</Entry>
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论