Вставить событие в текстовое поле WPF - PullRequest
61 голосов
/ 17 июня 2010

Я создал пользовательский элемент управления, наследующий TextBox. Этот пользовательский элемент управления является числовым TextBox, только с числами поддержки.

Я использую OnPreviewTextInput, чтобы проверить каждый набираемый новый символ, чтобы увидеть, является ли этот символ допустимым вводом. Это прекрасно работает. Однако, если я вставлю текст в TextBox, OnPreviewTextInput не будет запущен.

Как лучше всего захватывать вставленный текст в TextBox?

Кроме того, у меня проблема при нажатии на клавишу «пробел», я не могу понять, какое событие это сработает. OnPreviewTextInput не выстрелил!

Есть идеи, как захватить вставленный текст и события пробела в WPF TextBox?

Ответы [ 5 ]

116 голосов
/ 17 июня 2010

Вот некоторый код, который у меня лежал на случай, если он мне когда-нибудь понадобится. Могу вам помочь.

public Window1()
{
    InitializeComponent();

    // "tb" is a TextBox
    DataObject.AddPastingHandler(tb, OnPaste);
}

private void OnPaste(object sender, DataObjectPastingEventArgs e)
{
    var isText = e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
    if (!isText) return;

    var text = e.SourceDataObject.GetData(DataFormats.UnicodeText) as string;
    ...
}
14 голосов
/ 17 июня 2010

Проблема с попыткой перехватить и перехватить все отдельные события, которые могут вызвать изменение свойства TextBox.Text, состоит в том, что существует много таких событий:

  • TextInput: пользовательские типы
  • KeyDown: Delete, Backspace, Enter, IME
  • Командные жесты: Ctrl-X, Ctrl-Y, Ctrl-V, Ctrl-X
  • MouseDown: кнопка вставки, кнопка вырезания, кнопка отмены, ...
  • Щелчок: пробел нажимается, когда кнопки Вставить, Вырезать, Отменить имеют локальный фокус
  • RaiseEvent: код вызывает команды Вставить, Вырезать, Отменить, Повторить
  • Доступность: голосовые команды, клавиатура Брайля и т. Д.

Попытка надежно перехватить все это бесполезное упражнение. Гораздо лучшим решением является мониторинг TextBox.TextChanged и отклонение изменений, которые вам не нравятся.

В этот ответ Я покажу, как реализовать класс TextBoxRestriction для конкретного запрашиваемого сценария. Эту же технику можно обобщить для использования с любыми ограничениями, которые вы хотите наложить на свой элемент управления TextBox.

Например, в вашем случае вы можете внедрить RestrictValidChars присоединенное свойство аналогично RestrictDeleteTo свойству в этом коде. Это будет то же самое, за исключением того, что внутренний цикл будет проверять вставки, а не удаления. Это будет использовано так:

<TextBox my:TextBoxRestriction.RestrictValidChars="0123456789" />

Это просто идея того, как с этим можно обращаться. Есть много способов структурировать ваш код в зависимости от того, что вы хотите. Например, вы можете изменить TextBoxRestriction, чтобы вызывать собственный код для проверки с использованием присоединенного свойства, которое принимает делегат или объект, содержащий событие.

См. В другом ответе подробности о том, как связать свойство Text, когда вы используете класс TextBoxRestriction, чтобы оно не вызывало ограничение, когда вы этого не хотите.

7 голосов
/ 17 июня 2010

Для возврата, пожалуйста, проверьте PreviewKeyDown событие

Для команды вставки добавьте привязку команды к ApplicationCommands.Paste и установите аргумент для обработки, если вы не хотите ничего с ним делать:

<Window.CommandBindings>
  <CommandBinding Command="ApplicationCommands.Paste"
                  Executed="PasteExecuted" />
</Window.CommandBindings>

И в коде позади:

private void PasteExecuted(object sender, ExecutedRoutedEventArgs e)
{
    e.Handled = true;
}
2 голосов
/ 27 марта 2011

Этого можно добиться с помощью события PreviewKeyDown и события TextChanged.

В PreviewKeyDown захватить операцию вставки

if(Key.V == e.Key && Keyboard.Modifiers == ModifierKeys.Control)
{
   strPreviousString = this.txtNumber.Text;
   bIsPasteOperation = true;
}

В TextChanged событие

if (true == bIsPasteOperation)
{

   if (false == this.IsNumber(this.txtNumber.Text))
   {
      this.txtNumber.Text = strPreviousString;
      e.Handled = true;
   }
   bIsPasteOperation = false;
}

Где IsNumber метод проверяет, введенный текст является числом или нет

private bool IsNumber(string text)
{
   int number;

   //Allowing only numbers
   if (!(int.TryParse(text, out number)))
   {
      return false;
   }
   return true
}
0 голосов
/ 22 марта 2019

Это работает довольно хорошо для меня. Я хотел изменить цвет текстового поля, когда пользователь внес изменения в содержимое.

  • принимать цифры, включая точки и отрицательные символы
  • набранные клавиши: delete, backspace, Ctrl-V (вставить), Ctrl-X (вырезать)
  • щелчок правой кнопкой мыши для вставки и вырезания

Мне удалось добиться этого с помощью 3 событий ниже:

    public bool IsDirty {
        set {
            if(value) {
                txtValue.Background = Brushes.LightBlue;
            } else {
                txtValue.Background = IsReadOnly ? Brushes.White : Brushes.LightYellow;
            }
        }
        get {
            return txtValue.Background == Brushes.LightBlue;
        }
    }

    private void PreviewTextInput(object sender, TextCompositionEventArgs e) {
        TextBox tb = ((TextBox)sender);
        string originalText = tb.Text;
        string newVal = "";

        //handle negative
        if (e.Text=="-") {
            if(originalText.IndexOf("-") > -1 || tb.CaretIndex != 0 || originalText == "" || originalText == "0") {
                //already has a negative or the caret is not at the front where the - should go
                //then ignore the entry
                e.Handled = true;
                return;
            }

            //put it at the front
            newVal = e.Text + originalText;
        } else {
            //normal typed number
            newVal = originalText + e.Text;
        }

        //check if it's a valid double if so then dirty
        double dVal;
        e.Handled = !double.TryParse(newVal, out dVal);
        if(!e.Handled) {
            IsDirty = true;
        }
    }

    private void PreviewKeyUp(object sender, KeyEventArgs e) {
        //handle paste
        if ((Key.V == e.Key || Key.X == e.Key) && Keyboard.Modifiers ==  ModifierKeys.Control) {
            IsDirty = true;
        }
        //handle delete and backspace
        if (e.Key == Key.Delete || e.Key == Key.Back) {
            IsDirty = true;
        }
    }


    private void PreviewExecuted(object sender, ExecutedRoutedEventArgs e) {
        //handle context menu cut/paste
        if (e.Command == ApplicationCommands.Cut || e.Command == ApplicationCommands.Paste) {
            IsDirty = true;
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...