下面您将找到附加属性的代码,可以像这样使用它来防止从文本框删除除“(”或“)”之外的任何内容。
<TextBox my:TextBoxRestriction.RestrictDeleteTo="()" ... />
这将正确处理所有鼠标和键盘更新,例如:
- 选择多个字符时使用删除键
- 退格键的使用
- 使用 Ctrl-X 进行剪切
- 单击菜单栏上的“剪切”按钮
正因为如此,它比简单地拦截 PreviewKeyDown 功能要强大得多。
这还会通过直接分配给 .Text 属性来禁用通过“(”或“)”删除任何内容,因此这将失败:
textBox.Text = "Good morning";
因此,TextBoxRestriction 类还包含另一个附加属性,称为不受限制的文本设置后,可以绕过限制更新 Text 属性。这可以在代码中使用设置TextBoxRestriction.SetUnrestrictedText
,或像这样的数据绑定:
<TextBox my:TextBoxRestriction.RestrictDeleteTo="()"
my:TextBoxRestriction.UnrestrictedText="{Binding PropertyNameHere}" />
在下面的实现中,UnrestrictedText 仅在还设置了 RestrictDeleteTo 时才起作用。可以进行完整的实现,每当设置任一属性时就注册事件处理程序,并将处理程序保存在第三个附加属性中以供以后取消注册。但对于您当前的需求来说,这可能是不必要的。
这是承诺的实现:
public class TextBoxRestriction : DependencyObject
{
// RestrictDeleteTo: Set this to the characters that may be deleted
public static string GetRestrictDeleteTo(DependencyObject obj) { return (string)obj.GetValue(RestrictDeleteToProperty); }
public static void SetRestrictDeleteTo(DependencyObject obj, string value) { obj.SetValue(RestrictDeleteToProperty, value); }
public static readonly DependencyProperty RestrictDeleteToProperty = DependencyProperty.RegisterAttached("RestrictDeleteTo", typeof(string), typeof(TextBoxRestriction), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var box = (TextBox)obj;
box.TextChanged += (obj2, changeEvent) =>
{
var oldText = GetUnrestrictedText(box);
var allowedChars = GetRestrictDeleteTo(box);
if(box.Text==oldText || allowdChars==null) return;
foreach(var change in changeEvent.Changes)
if(change.RemovedLength>0)
{
string deleted = box.Text.Substring(change.Offset, change.RemovedLength);
if(deleted.Any(ch => !allowedChars.Contains(ch)))
box.Text = oldText;
}
SetUnrestrictedText(box, box.Text);
};
}
});
// UnrestrictedText: Bind or access this property to update the Text property bypassing all restrictions
public static string GetUnrestrictedText(DependencyObject obj) { return (string)obj.GetValue(UnrestrictedTextProperty); }
public static void SetUnrestrictedText(DependencyObject obj, string value) { obj.SetValue(UnrestrictedTextProperty, value); }
public static readonly DependencyProperty UnrestrictedTextProperty = DependencyProperty.RegisterAttached("UnrestrictedText", typeof(string), typeof(TextBoxRestriction), new PropertyMetadata
{
DefaultValue = "",
PropertyChangedCallback = (obj, e) =>
{
var box = (TextBox)obj;
box.Text = (string)e.NewValue;
}
});
}
工作原理:当您设置 UnrestrictedText 时,它会设置 Text,反之亦然。 TextChanged 处理程序检查 Text 是否与 UnrestrictedText 不同。如果是这样,它就知道文本已通过设置 UnrestrictedText 之外的某种其他机制进行了更新,因此会扫描更改以查找非法删除。如果找到,它将 Text 设置回仍存储在 UnrestrictedText 中的值,从而阻止更改。