文化差异下的数字输入解决方案

在全球化的今天,软件开发者经常需要面对不同文化背景下的用户输入习惯。例如,在意大利,小数点通常使用逗号表示,而不是点。这在开发应用程序时可能会带来一些挑战,尤其是当涉及到数字输入时。本文将探讨这个问题,并提供一个解决方案。

问题描述

许多不使用点作为小数分隔符的用户可能已经注意到,无论操作系统设置如何,数字键盘上发出的字符总是点。如果输入了错误的字符,数字可能不会被识别为有效值(有时甚至更糟,因为它被误认为是有效的)。如果尝试打开记事本或任何原始输入应用程序,会发现没有办法“破解”Windows设置,以便将数字键盘上的“点”正确输入为逗号。顺便说一句,如果在Microsoft Excel中输入数字,字符实际上是逗号。看起来翻译是由应用程序管理的。

然而,这并不简单。想象一下编写自己的应用程序(以WPF为例),并有一系列文本框。虽然用于输入数字的文本框(例如大多数物理单位)使用逗号进行“翻译”是没有问题的,但用于IP模式的另一个文本框显然不应该在任何时候被翻译。

看起来一些国家对一般数字和货币使用不同的标点符号:“邻居”瑞士朋友对任何数字使用逗号,但在货币方面更喜欢点。

解决方案

这里有一个解决方案,但相信很难满足所有开发者的习惯。选择了一个简单的附加属性,作为任何TextBoxBase对象的“行为”,它“拦截”小数键(numpad的DP)并用适当的字符替换它。

以下是C#代码实现:

namespace DecimalPointCorrectorDemo { public enum DecimalPointCorrectionMode { Inherits, Number, Currency, Percent, } public static class TextBoxHelper { public static readonly DependencyProperty DecimalPointCorrectionProperty = DependencyProperty.RegisterAttached( "DecimalPointCorrection", typeof(DecimalPointCorrectionMode), typeof(TextBoxHelper), new UIPropertyMetadata(default(DecimalPointCorrectionMode), DecimalPointCorrectionChanged) ); public static DecimalPointCorrectionMode GetDecimalPointCorrection(TextBoxBase obj) { return (DecimalPointCorrectionMode)obj.GetValue(DecimalPointCorrectionProperty); } public static void SetDecimalPointCorrection(TextBoxBase obj, DecimalPointCorrectionMode value) { obj.SetValue(DecimalPointCorrectionProperty, value); } private static void DecimalPointCorrectionChanged(object sender, DependencyPropertyChangedEventArgs args) { var tbox = (TextBoxBase)sender; switch ((DecimalPointCorrectionMode)args.OldValue) { case DecimalPointCorrectionMode.Number: case DecimalPointCorrectionMode.Currency: case DecimalPointCorrectionMode.Percent: tbox.PreviewKeyDown -= tbox_PreviewKeyDown; break; } switch ((DecimalPointCorrectionMode)args.NewValue) { case DecimalPointCorrectionMode.Number: case DecimalPointCorrectionMode.Currency: case DecimalPointCorrectionMode.Percent: tbox.PreviewKeyDown += tbox_PreviewKeyDown; break; } } static void tbox_PreviewKeyDown(object sender, KeyEventArgs e) { if (e.Key == System.Windows.Input.Key.Decimal) { e.Handled = true; var tbox = (TextBoxBase)sender; var mode = TextBoxHelper.GetDecimalPointCorrection(tbox); var culture = Thread.CurrentThread.CurrentCulture; SimulateDecimalPointKeyPress(tbox, mode, culture); } } private static async void SimulateDecimalPointKeyPress(TextBoxBase tbox, DecimalPointCorrectionMode mode, CultureInfo culture) { string replace; switch (mode) { case DecimalPointCorrectionMode.Number: replace = culture.NumberFormat.NumberDecimalSeparator; break; case DecimalPointCorrectionMode.Currency: replace = culture.NumberFormat.CurrencyDecimalSeparator; break; case DecimalPointCorrectionMode.Percent: replace = culture.NumberFormat.PercentDecimalSeparator; break; default: replace = null; break; } if (!string.IsNullOrEmpty(replace)) { var tc = new TextComposition(InputManager.Current, tbox, replace); TextCompositionManager.StartComposition(tc); } await Task.FromResult(false); } } }

代码相当简单,认为没有必要再详细讨论了。唯一值得一提的是按键替换函数中的“异步”模式。只是想让原始事件(PreviewKeyDown)在添加另一个(可能的)事件之前有一点时间来完成。老实说,不知道这是否真的必要:异步-等待模式既容易又可靠,所以更倾向于保持代码更安全。欢迎改进。

完整的演示解决方案源代码可以。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485