如何在WPF中跟踪TextBox中删除的字符?

Ash*_*shu 6 wpf textbox wpf-controls

我想跟踪用户通过Delete或BackSpace Key删除哪个字符.

我正在处理文本框的TextBox_ChangedEvent.

我可以从TextChangedEventArgs e.Changes中提取已删除的字符,如果是,我该怎么做?

我想限制用户从TextBox中删除任何字符.我希望用户只能删除两个字符(让我们说"("或")")

请建议.

Ray*_*rns 9

您可以在下面找到可以像这样使用的附加属性的代码,以防止从TextBox,句点中删除除"("或")"之外的任何内容.

<TextBox my:TextBoxRestriction.RestrictDeleteTo="()" ... />
Run Code Online (Sandbox Code Playgroud)

这将正确处理所有鼠标和键盘更新,例如:

  1. 使用包含所选多个字符的Delete键
  2. 使用Backspace键
  3. 使用Ctrl-X剪切
  4. 单击菜单栏上的"剪切"按钮

因此,它比简单地拦截PreviewKeyDown更强大.

这也通过直接分配给.Text属性来禁止删除任何"("或")",所以这将失败:

textBox.Text = "Good morning";
Run Code Online (Sandbox Code Playgroud)

因此,TextBoxRestriction类还包含另一个名为UnrestrictedText的附加属性,该属性在设置时可以绕过限制更新Text属性.这可以在代码中使用TextBoxRestriction.SetUnrestrictedText,或者像这样设置数据:

<TextBox my:TextBoxRestriction.RestrictDeleteTo="()"
         my:TextBoxRestriction.UnrestrictedText="{Binding PropertyNameHere}" />
Run Code Online (Sandbox Code Playgroud)

在下面的实现中,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;
      }
  });

}
Run Code Online (Sandbox Code Playgroud)

工作原理:设置UnrestrictedText时,它设置Text,反之亦然.TextChanged处理程序检查Text是否与UnrestrictedText不同.如果是这样,它知道Text已经通过设置UnrestrictedText之外的其他机制进行了更新,因此会扫描更改以进行非法删除.如果找到一个,则将Text设置回仍存储在UnrestrictedText中的值,从而阻止更改.