c# - XAML - IValueConverter 和Behavior 相互冲突,导致发生无限循环

标签 c# xaml xamarin xamarin.forms

在 Xamarin Forms 应用程序中,我的 IValueConverter 和 Behaviour 相互冲突,导致发生无限循环。我创建了一个简单的应用程序来演示这个问题,可以下载(下面的链接),并且我在下面包含了相关代码。

以下是我在此场景中尝试实现的要求。

  1. 用户必须能够为 int 输入空值。
  2. 用户只能输入整数值。

对于#1,我在后端模型中使用了可为 null 的 int。如果我只使用“int”,那么如果该字段被清除,那么该字段最终将始终以“0”结束。因此,IValueConverter 实现 StringToIntConverter 用于将值从字符串转换为 int,如果传递空字符串,则该属性设置为 null。

对于#2,Behavior IntegerValidationBehavior 检查每次击键并消除任何非整数值(包括句点)。另外,对于这个例子,我只显示数字键盘。但是,它允许一些非整数字符,例如句点,因此需要 IntegerValidationBehavior。

对于普通输入来说效果很好。但如果你从“0”开始,然后输入另一个数字,它就会变得困惑,最终陷入无限循环。我已经在各种 XF 版本以及 iOS 和 Android 平台上验证了这一点。

如何更改代码以满足我的要求?

重现步骤

  1. 运行下面的 github 存储库中的演示
  2. 在输入框中输入“05”,应用会无限循环卡住

复制链接

https://github.com/JohnLivermore/SampleXamarinApp/tree/endlessloop

<小时/>

整数验证行为

public class IntegerValidationBehavior : Behavior<Entry>
{
    protected override void OnAttachedTo(Entry entry)
    {
        entry.TextChanged += OnEntryTextChanged;
        base.OnAttachedTo(entry);
    }

    protected override void OnDetachingFrom(Entry entry)
    {
        entry.TextChanged -= OnEntryTextChanged;
        base.OnDetachingFrom(entry);
    }

    private static void OnEntryTextChanged(object sender, TextChangedEventArgs args)
    {
        if (!string.IsNullOrWhiteSpace(args.NewTextValue))
        {
            //make sure all characters are numbers
            var isValid = args.NewTextValue.ToCharArray().All(x => char.IsDigit(x));

            ((Entry)sender).Text = isValid ? args.NewTextValue : args.NewTextValue.Remove(args.NewTextValue.Length - 1);
        }
    }
}
<小时/>

字符串到整数转换器

public class StringToIntConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return "";
        else
            return ((int)value).ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var val = value as string;

        if (string.IsNullOrWhiteSpace(val))
            return null;
        else
        {
            var result = 0;
            int.TryParse(val, out result);
            return result;
        }
    }
}
<小时/>

XAML

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:behaviors="clr-namespace:SampleApp"
             mc:Ignorable="d"
             x:Class="SampleApp.MainPage">

    <StackLayout>
        <Entry Keyboard="Numeric"
               Text="{Binding Model.Length, Mode=TwoWay, Converter={StaticResource StringToInt}}">
            <Entry.Behaviors>
                <behaviors:IntegerValidationBehavior />
            </Entry.Behaviors>
        </Entry>
        <Label Text="{Binding Model.LengthString}"
               TextColor="Black" />
        <Button Text="Process"
                Command="{Binding Process}" />
    </StackLayout>

</ContentPage>
<小时/>

型号

public class MainPageModel : FreshBasePageModel
{
    public MainPageModel()
    {
        Model = new Model();
    }

    public Model Model { get; set; }
}

public class Model : INotifyPropertyChanged
{
    private int? _length;

    public int? Length
    {
        get { return _length; }
        set { SetProperty(ref _length, value); }
    }

    protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(storage, value))
        {
            return false;
        }
        storage = value;
        OnPropertyChanged(propertyName);

        return true;
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

最佳答案

将下面的方法替换为 IntegerValidationBehavior 文件中的 OnEntryTextChanged 方法,并检查其是否有效。

private static void OnEntryTextChanged(object sender, TextChangedEventArgs args)
            {
                if (!string.IsNullOrWhiteSpace(args.NewTextValue))
                {

                    //make sure all characters are numbers
                    var isValid = args.NewTextValue.ToCharArray().All(x => char.IsDigit(x));

                    if (isValid && args.NewTextValue.Length > 1 && args.NewTextValue.StartsWith("0"))
                        return;

                    ((Entry)sender).Text = isValid ? args.NewTextValue : args.NewTextValue.Remove(args.NewTextValue.Length - 1);
                }
            }

关于c# - XAML - IValueConverter 和Behavior 相互冲突,导致发生无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60050005/

相关文章:

c# - 尽管设置了精度,但 MSSQL 表中的十进制数会四舍五入

c# - WPF Datepicker 日历按钮不起作用(使用修改后的模板)

c# - JSON.Net 将内部对象转换为 C# 模型

android - Xamarin Visual Studio 2017 预览器不工作

ios - Xamarin.iOS 10.14/.NET Standard 2.0 支持哪些版本的 iOS?

ios - 苹果关于 HTTPs 和 iPv6 的新安全政策-澄清

c# - 为TimePicker设置24小时制时间格式

c# - 放大或缩小时如何使 Canvas 区域在 ScrollViewer 中居中,而不是所有内容都可以显示在查看窗口中

c# - 如何在没有 Process 类的情况下在 Windows 8 文件资源管理器中打开应用程序文件夹?

c# - 在 Xamarin.Android 中找不到与给定名称(在 'headerLayout' 处)匹配的资源