首页 > 解决方案 > Xamarin 表单条目小数分隔符在不同的 CultureInfo 上无法正常工作

问题描述

我在 xaml 中有一个条目:

<Entry Grid.Column="1" Grid.RowSpan="1"
                                   FontAttributes="None" FontSize="Large"
                                   IsPassword="False" Keyboard="Numeric"
                                   HorizontalTextAlignment="Center" VerticalOptions="StartAndExpand"
                                   Text="{Binding MyNumber}"
                                   TextColor="{Binding PropertyTextColor, Converter={StaticResource StringToColorConverter}}"
                                   Completed="Entry_Completed"/>

当我有美国文化信息时,一切正常,但是当文化信息发生变化时,我无法输入逗号或点分隔符进行十进制输入。例如,当我键入 5 并输入 ',' 并键入 5 时,该值将转换为 55。我尝试更改当前线程的区域性信息,但它没有帮助。

    private decimal _myNumber;
    public decimal MyNumber
    {
        get
        {
            return myNumber;
        }
        set
        {
            System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
            if (_myNumber != value)
            {
                if (IsDivisible)
                    //_myNumber = Convert.ToDecimal(Math.Round(value, 2).ToString(), new CultureInfo("pl-PL"));
                    _ = decimal.TryParse(value.ToString(), NumberStyles.Any, new CultureInfo("pl-PL"), out _count);
                else
                    _ = decimal.TryParse(value.ToString(), NumberStyles.Any, new CultureInfo("pl-PL"), out _count);
                 // _myNumber = Convert.ToDecimal(Math.Round(value, 0).ToString(), new CultureInfo("pl-PL"));

                OnPropertyChanged(nameof(Count));
            }
        }
    }

有没有办法解决这个问题?因为据我了解,此问题与三星配置或设置有关,并且在 Xamarin 中是一个很常见的问题。

标签: c#.netxamarinxamarin.forms

解决方案


在我的情况下,我最终需要强制将点作为每种文化的小数分隔符。为了打印点,我还需要为条目创建一个自定义渲染器,以便重新设置 InputTypes 标志。

如果这听起来像是您可能想要遵循的方式,请继续阅读。

下面是一个示例最少的应用程序,用于演示如何在 Android 中为 Xamarin.Forms 强制和使用点作为小数分隔符

强制点作为小数分隔符

首先我们要告诉 App,无论使用什么文化,点都必须作为小数分隔符:

public App()
{
    CultureInfo customCulture = (CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
    customCulture.NumberFormat.NumberDecimalSeparator = ".";

    System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;

    InitializeComponent();

    MainPage = new MainPage();
}

重新设置输入类型

在 Xamarin.Forms 共享项目上创建一个 CustomEntry:

using Xamarin.Forms;

namespace EntryDecimal
{
    public class MyCustomEntry : Entry
    {
    }
}

然后在 Android 上添加自定义渲染器。为此,只需向 Android 项目添加一个名为 AndroidCustomEntryRenderer.cs 的新类,其内容如下:

using System.ComponentModel;

using Android.Widget;

using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

using Android.Text.Method;
using Android.Content;
using EntryDecimal.Droid;
using EntryDecimal;

[assembly: ExportRenderer(typeof(MyCustomEntry), typeof(AndroidCustomEntryRenderer))]
namespace EntryDecimal.Droid
{
    public class AndroidCustomEntryRenderer : EntryRenderer
    {
        private MyCustomEntry element;
        private EditText native;

        public AndroidCustomEntryRenderer(Context context) : base(context)
        { }

        protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
        {
            base.OnElementChanged(e);

            //Java.Text.DecimalFormatSymbols.Instance.DecimalSeparator = '.';

            element = (MyCustomEntry)Element ?? null;
            native = Control as EditText;

            UpdateKeyboard();
        }


        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (Control == null) return;

            else if (e.PropertyName == InputView.KeyboardProperty.PropertyName)
                UpdateKeyboard();
        }

        private void UpdateKeyboard()
        {
            //Implementation of the numeric keyboard (we simply add the NumberFlagSigned)
            native = Control as EditText;

            var defaultNumericKeyboard = Android.Text.InputTypes.ClassNumber | Android.Text.InputTypes.NumberFlagDecimal;
            var correnctNumericKeyboard = Android.Text.InputTypes.ClassNumber | Android.Text.InputTypes.NumberFlagSigned | Android.Text.InputTypes.NumberFlagDecimal;

            if (native.InputType == defaultNumericKeyboard)
            {
                native.InputType =
                Android.Text.InputTypes.ClassNumber |
                Android.Text.InputTypes.NumberFlagSigned |
                Android.Text.InputTypes.NumberFlagDecimal;
                native.KeyListener = DigitsKeyListener.GetInstance(string.Format("7890.-"));
            }
            else if (native.InputType == correnctNumericKeyboard)
            {
                // Even though in the next line the InputType is set to the same it is already set, this seems to 
                // fix the problem with the decimal separator: Namely, a local other than english is set, the point 
                // does not have any effect in the numeric keyboard. Re-setting the InputType seems to fix this.
                native.InputType =
                Android.Text.InputTypes.ClassNumber |
                Android.Text.InputTypes.NumberFlagSigned |
                Android.Text.InputTypes.NumberFlagDecimal;
            }
        }
        
    }
}

最后消费这个:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:EntryDecimal"
             x:Class="EntryDecimal.MainPage">

    <StackLayout>
        <local:MyCustomEntry x:Name="MyEntry"  Keyboard="Numeric"
               WidthRequest="150"
               HorizontalOptions="CenterAndExpand"
               VerticalOptions="CenterAndExpand"
                             Completed="MyCustomEntry_Completed"/>
    </StackLayout>

</ContentPage>

这个最小的空白应用程序在我这边工作正常,接受点作为任何文化的小数分隔符(例如 de [german],其中小数分隔符是“,”)。

希望这有效!


推荐阅读