Как отследить, какой символ удален в TextBox в WPF?

Я хочу отследить, какой символ удален пользователем через, Удаляют или клавиша Backspace.

Я обрабатываю TextBox_ChangedEvent текстового поля.

Я могу извлечь удаленный символ из TextChangedEventArgs e. Изменения и если да, Как я могу сделать это?

Я хочу ограничить пользователя от удаления любых символов от TextBox. Я хочу пользователя, может удалить только два символа (скажем," (" или")")

Предложите.

6
задан Ashish Ashu 16 June 2010 в 08:08
поделиться

3 ответа

Ниже вы найдете код для прикрепленного свойства, которое можно использовать таким образом для предотвращения чего-либо, кроме "(" или ") "от удаления из текстового поля, точка.

<TextBox my:TextBoxRestriction.RestrictDeleteTo="()" ... />

Это будет правильно обрабатывать все обновления мыши и клавиатуры, такие как:

  1. Использование клавиши Delete с несколькими выбранными символами
  2. Использование клавиши Backspace
  3. Использование Ctrl-X для вырезания
  4. Щелчок кнопка «Вырезать» в строке меню

Благодаря этому она намного мощнее простого перехвата PreviewKeyDown.

Это также запрещает удаление чего-либо byt "(" или ")" путем непосредственного присвоения свойству .Text, поэтому это не удастся:

textBox.Text = "Good morning";

Из-за этого класс TextBoxRestriction также содержит еще одно присоединенное свойство, называемое UnrestrictedText , который, если установлен, может обновлять свойство 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, он устанавливает текст и наоборот. Обработчик TextChanged проверяет, отличается ли Text от UnrestrictedText.Если это так, он знает, что Text был обновлен каким-то другим механизмом, кроме установки UnrestrictedText, поэтому он сканирует изменения на предмет незаконного удаления. Если он обнаружен, он устанавливает для Text значение, которое все еще хранится в UnrestrictedText, предотвращая изменение.

9
ответ дан 10 December 2019 в 00:33
поделиться

Я не знаю WPF, но предполагаю, что для этого он такой же, как WinForms (кажется вероятным). Единственный способ, о котором я знаю, - это то, что вы фактически сохраняете текущий текст в переменной и при изменении текста, если это не удаление или возврат, вы обновляете этот текст, в противном случае вы используете его, сравнивайте, что изменилось, и следует ли разрешить это изменение.

Изменить: глядя на TextChangedEventArgs.Changes , кажется, что способ, который я описал выше, все еще может быть подходящим, но вы могли бы использовать Changes для сравнения текстов более эффективно.

Вы, возможно, уже думали об этом, но в противном случае не забудьте также обрабатывать вырезание и вставку (и что пользователь может делать это с помощью мыши, а не клавиатуры).

0
ответ дан 10 December 2019 в 00:33
поделиться

Прикрепленное поведение для его обработки

public static class TextInputBehaviour
{
    public static bool GetIsDeleteRestricted(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsDeleteRestrictedProperty);
    }

    public static void SetIsDeleteRestricted(DependencyObject obj, bool value)
    {
        obj.SetValue(IsDeleteRestrictedProperty, value);
    }

    public static readonly DependencyProperty IsDeleteRestrictedProperty=DependencyProperty.RegisterAttached("IsDeleteRestricted", typeof(bool), typeof(TextInputBehaviour), new UIPropertyMetadata(false, OnIsDeleteRestrictedChanged));
}

private static void OnIsDeleteRestrictedChanged(object sender, DependencyPropertyChangedEventArgs e)
{      
  TextBox textBox = (TextBox)sender;
  bool isDeleteRestricted = (bool)(e.NewValue);

  if (isDeleteRestricted)
    textBox.PreviewKeyDown += RestrictDeleteKey;
  else
    textBox.PreviewKeyDown -= RestrictDeleteKey;
}

private static void RestrictDeleteKey(object sender, KeyEventArgs e)
{
      e.Handled = (e.Key == Key.Delete);
}

Отбросьте поведение в разделе ресурсов

Затем в блоке разметки текстового поля установите поведение

<TextBox local:TextInputBehaviour.IsDeleteRestricted="True" />
1
ответ дан 10 December 2019 в 00:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: