MAUI: 自定义行为挂起

huangapple go评论95阅读模式
英文:

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), &quot;cl&quot;);
public string Iso2Country
{
get =&gt; (string)GetValue(Iso2CountryProperty);
set =&gt; SetValue(Iso2CountryProperty, value);
}
public static bool ChileValidate(string docNumber)
{
string rut = CleanRegex().Replace(docNumber, string.Empty).ToUpper();
if (rut.Length &gt;= 2)
{
string dv = rut[rut.Length - 1].ToString();
if (MatchRegex().IsMatch(dv))
{
int largo = rut.Length;
if (largo &gt; 10 || largo &lt; 2) return false;
// La parte del RUT debe ser un n&#250;mero entero
if (int.TryParse(rut.AsSpan(0, largo - 1), out _))
{
// El d&#237;gito verificador debe ser un n&#250;mero o la K
if ((rut[largo - 1].CompareTo(&#39;0&#39;) &lt; 0 || rut[largo - 1].CompareTo(&#39;9&#39;) &gt; 0) &amp;&amp; rut[largo - 1] != &#39;K&#39;)
return false;
// Realiza la operaci&#243;n m&#243;dulo
int suma = 0;
int mul = 2;
// -2 porque rut contiene el d&#237;gito verificador, el cual no hay que considerar
for (int i = rut.Length - 2; i &gt;= 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 = &#39;K&#39;;
else if (residuo == 0)
dvr = &#39;0&#39;;
else
dvr = (11 - residuo).ToString()[0];
return dvr.Equals(rut[^1]);
}
}
}
return false;
}
protected override async ValueTask&lt;bool&gt; ValidateAsync(string value, CancellationToken token)
{
bool result = true;
string iso2 = Iso2Country ?? string.Empty;
switch (iso2)
{
case &quot;cl&quot;:
result = ChileValidate(value);
break;
}
return result &amp;&amp; await base.ValidateAsync(value, token);
}
[GeneratedRegex(&quot;[ .-]&quot;)]
private static partial Regex CleanRegex();
[GeneratedRegex(&quot;[0-9K]&quot;)]
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方法,它可以被触发。首先,我看到iso2Iso2Country的值始终是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:

&lt;ContentPage xmlns=&quot;http://schemas.microsoft.com/dotnet/2021/maui&quot;
xmlns:x=&quot;http://schemas.microsoft.com/winfx/2009/xaml&quot;
x:Class=&quot;MauiApp4.NewPage2&quot;
xmlns:mybehavior=&quot;clr-namespace:MauiAppTest&quot;
xmlns:toolkit=&quot;http://schemas.microsoft.com/dotnet/2022/maui/toolkit&quot;
Title=&quot;NewPage2&quot;&gt;
&lt;ContentPage.Resources&gt;
&lt;Style x:Key=&quot;InvalidEntryStyle&quot; TargetType=&quot;Entry&quot;&gt;
&lt;Setter Property=&quot;TextColor&quot; Value=&quot;Blue&quot; /&gt;
&lt;/Style&gt;
&lt;Style x:Key=&quot;ValidEntryStyle&quot; TargetType=&quot;Entry&quot;&gt;
&lt;Setter Property=&quot;TextColor&quot; Value=&quot;Green&quot; /&gt;
&lt;/Style&gt;
&lt;/ContentPage.Resources&gt;
&lt;Entry x:Name=&quot;entry&quot;&gt;
&lt;Entry.Behaviors&gt;
&lt;mybehavior:SsnValidationBehavior
InvalidStyle=&quot;{StaticResource InvalidEntryStyle}&quot;
ValidStyle=&quot;{StaticResource ValidEntryStyle}&quot;
Flags=&quot;ValidateOnValueChanged&quot;
MinimumLength=&quot;1&quot;
MaximumLength=&quot;10&quot; /&gt;
&lt;/Entry.Behaviors&gt;
&lt;/Entry&gt;
&lt;/ContentPage&gt;

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 &amp;&amp; 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:

&lt;Entry x:Name=&quot;entry&quot;&gt;
&lt;Entry.Triggers&gt;
&lt;DataTrigger TargetType=&quot;Entry&quot; Binding=&quot;{Binding Source={x:Reference entry}, Path=Text}&quot; Value=&quot;{x:Null}&quot;&gt;
&lt;Setter Property=&quot;BackgroundColor&quot; Value=&quot;Pink&quot;/&gt;
&lt;/DataTrigger&gt;
&lt;DataTrigger TargetType=&quot;Entry&quot; Binding=&quot;{Binding Source={x:Reference entry}, Path=Text.Length}&quot; Value=&quot;0&quot;&gt;
&lt;Setter Property=&quot;BackgroundColor&quot; Value=&quot;Pink&quot;/&gt;
&lt;/DataTrigger&gt;
&lt;/Entry.Triggers&gt;
&lt;/Entry&gt;
</details>

huangapple
  • 本文由 发表于 2023年6月22日 08:35:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76527956.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定