这听起来像是特定于视图的逻辑,所以我认为没有理由不使用视图隐藏代码来控制它。就我个人而言,我会在丢弃任何非数字字符的PreviewKeyDown
on 上实现这种行为。TextBox
拥有可以重用的通用控件可能不会有什么坏处,例如自定义控件NumbersOnlyTextBox
,或者AttachedProperty
您可以附加到您的控件TextBox
以指定它只允许数字。
事实上,我记得创建了一个附加属性,允许您为文本框指定一个正则表达式,它会将字符输入限制为该正则表达式。我有一段时间没有使用它了,所以你可能想要测试它或者可能更新它,但这里是代码。
// When set to a Regex, the TextBox will only accept characters that match the RegEx
#region AllowedCharactersRegex Property
/// <summary>
/// Lets you enter a RegexPattern of what characters are allowed as input in a TextBox
/// </summary>
public static readonly DependencyProperty AllowedCharactersRegexProperty =
DependencyProperty.RegisterAttached("AllowedCharactersRegex",
typeof(string), typeof(TextBoxProperties),
new UIPropertyMetadata(null, AllowedCharactersRegexChanged));
// Get
public static string GetAllowedCharactersRegex(DependencyObject obj)
{
return (string)obj.GetValue(AllowedCharactersRegexProperty);
}
// Set
public static void SetAllowedCharactersRegex(DependencyObject obj, string value)
{
obj.SetValue(AllowedCharactersRegexProperty, value);
}
// Events
public static void AllowedCharactersRegexChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var tb = obj as TextBox;
if (tb != null)
{
if (e.NewValue != null)
{
tb.PreviewTextInput += Textbox_PreviewTextChanged;
DataObject.AddPastingHandler(tb, TextBox_OnPaste);
}
else
{
tb.PreviewTextInput -= Textbox_PreviewTextChanged;
DataObject.RemovePastingHandler(tb, TextBox_OnPaste);
}
}
}
public static void TextBox_OnPaste(object sender, DataObjectPastingEventArgs e)
{
var tb = sender as TextBox;
bool isText = e.SourceDataObject.GetDataPresent(DataFormats.Text, true);
if (!isText) return;
var newText = e.SourceDataObject.GetData(DataFormats.Text) as string;
string re = GetAllowedCharactersRegex(tb);
re = "[^" + re + "]";
if (Regex.IsMatch(newText.Trim(), re, RegexOptions.IgnoreCase))
{
e.CancelCommand();
}
}
public static void Textbox_PreviewTextChanged(object sender, TextCompositionEventArgs e)
{
var tb = sender as TextBox;
if (tb != null)
{
string re = GetAllowedCharactersRegex(tb);
re = "[^" + re + "]";
if (Regex.IsMatch(e.Text, re, RegexOptions.IgnoreCase))
{
e.Handled = true;
}
}
}
#endregion // AllowedCharactersRegex Property
它将像这样使用:
<TextBox Text="{Binding SearchString, UpdateSourceTrigger=PropertyChanged}"
local:TextBoxHelpers.AllowedCharactersRegex="[0-9]" />
但至于为什么它不会更新 UI。UI 知道该值实际上并未更改,因此当它收到 PropertyChange 通知时不会费心重新评估绑定。
为了解决这个问题,您可以尝试在将其设置为正则表达式值之前暂时将该值设置为其他值,并引发PropertyChange
通知以便 UI 重新评估绑定,但老实说,这并不是一个理想的解决方案。
private string _searchString;
public string SearchString
{
get
{
return _searchString;
}
set
{
value = Regex.Replace(value, "[^0-9]", string.Empty);
// If regex value is the same as the existing value,
// change value to null to force bindings to re-evaluate
if (_searchString == value)
{
_searchString = null;
DoNotifyPropertyChanged("SearchString");
}
_searchString = value;
DoNotifyPropertyChanged("SearchString");
}
}