web-dev-qa-db-ja.com

WPF TextBoxにイベントを貼り付け

TextBoxを継承するカスタムコントロールを作成しました。このカスタムコントロールは数値TextBoxであり、数字のみをサポートしています。

私はOnPreviewTextInputを使用して、入力されている新しい文字をチェックして、その文字が有効な入力であるかどうかを確認しています。これはうまく機能します。ただし、テキストをTextBoxに貼り付けると、OnPreviewTextInputは起動されません。

TextBoxに貼り付けられたテキストをキャプチャする最良の方法は何ですか?

また、バックスペースを押すと問題が発生します。これによりどのイベントが発生するかわかりません。 OnPreviewTextInputは実行されません!

WPF TextBoxで貼り付けられたテキストとバックスペースイベントをキャプチャする方法はありますか?

61
code-zoop

これが必要になった場合に備えて、私がうろついていたコードをいくつか示します。あなたを助けるかもしれません。

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;
    ...
}
120
Matt Hamilton

TextBox.Textプロパティを変更する可能性のある個々のイベントをすべてインターセプトおよびトラップしようとすると、そのようなイベントが多数発生するという問題があります。

  • TextInput:ユーザータイプ
  • キーダウン:削除、バックスペース、Enter、IME
  • コマンドジェスチャ:Ctrl-X、Ctrl-Y、Ctrl-V、Ctrl-X
  • MouseDown:[貼り付け]ボタン、[切り取り]ボタン、[元に戻す]ボタン、...
  • クリック:貼り付け、切り取り、元に戻すボタンにローカルフォーカスがあるときにスペースバーを押す
  • RaiseEvent:コードは、Paste、Cut、Undo、Redoコマンドを発生させます
  • アクセシビリティ:音声コマンド、点字キーボードなど

これらすべてを確実に傍受しようとするのは無益です。より良い解決策は、TextBox.TextChangedを監視し、気に入らない変更を拒否することです。

この回答 では、質問されている特定のシナリオにTextBoxRestrictionクラスを実装する方法を示しています。これと同じ手法を一般化して、TextBoxコントロールに制限を加えて使用することができます。

たとえば、あなたの場合、そのコードのRestrictValidCharsプロパティと同様に、RestrictDeleteTo添付プロパティを実装することができます。内側のループが削除ではなく挿入をチェックすること以外は同じです。次のように使用されます。

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

これは、それがどのように処理されるかのアイデアにすぎません。目的に応じてコードを構造化する方法は多数あります。たとえば、TextBoxRestrictionを変更して独自のコードを呼び出し、デリゲートまたはイベントを含むオブジェクトを受け取る添付プロパティを使用して検証できます。

TextBoxRestrictionクラスを使用しているときにTextプロパティをバインドする方法の詳細については、他の回答を参照してください。そうしないと、制限がトリガーされません。

14
Ray Burns

バックスペースについては、 PreviewKeyDown イベントを確認してください

貼り付けコマンドの場合は、ApplicationCommands.Pasteにコマンドバインドを追加し、何も処理しない場合は引数を処理済みに設定します。

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

そして、コードビハインドでは:

private void PasteExecuted(object sender, ExecutedRoutedEventArgs e)
{
    e.Handled = true;
}
7
Arcturus

これは、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
}
2
Syed

これは私にとってはかなりうまく機能します。ユーザーがコンテンツを変更したときに、テキストボックスの色を変更したかった。

  • ピリオドと負の文字を含む数字を受け入れます
  • 入力されたキー:削除、バックスペース、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;
        }
    }
0
JJ_Coder4Hire