TextBox
を継承するカスタムコントロールを作成しました。このカスタムコントロールは数値TextBox
であり、数字のみをサポートしています。
私はOnPreviewTextInput
を使用して、入力されている新しい文字をチェックして、その文字が有効な入力であるかどうかを確認しています。これはうまく機能します。ただし、テキストをTextBox
に貼り付けると、OnPreviewTextInput
は起動されません。
TextBox
に貼り付けられたテキストをキャプチャする最良の方法は何ですか?
また、バックスペースを押すと問題が発生します。これによりどのイベントが発生するかわかりません。 OnPreviewTextInput
は実行されません!
WPF TextBox
で貼り付けられたテキストとバックスペースイベントをキャプチャする方法はありますか?
これが必要になった場合に備えて、私がうろついていたコードをいくつか示します。あなたを助けるかもしれません。
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;
...
}
TextBox.Textプロパティを変更する可能性のある個々のイベントをすべてインターセプトおよびトラップしようとすると、そのようなイベントが多数発生するという問題があります。
これらすべてを確実に傍受しようとするのは無益です。より良い解決策は、TextBox.TextChangedを監視し、気に入らない変更を拒否することです。
この回答 では、質問されている特定のシナリオにTextBoxRestrictionクラスを実装する方法を示しています。これと同じ手法を一般化して、TextBoxコントロールに制限を加えて使用することができます。
たとえば、あなたの場合、そのコードのRestrictValidChars
プロパティと同様に、RestrictDeleteTo
添付プロパティを実装することができます。内側のループが削除ではなく挿入をチェックすること以外は同じです。次のように使用されます。
<TextBox my:TextBoxRestriction.RestrictValidChars="0123456789" />
これは、それがどのように処理されるかのアイデアにすぎません。目的に応じてコードを構造化する方法は多数あります。たとえば、TextBoxRestrictionを変更して独自のコードを呼び出し、デリゲートまたはイベントを含むオブジェクトを受け取る添付プロパティを使用して検証できます。
TextBoxRestrictionクラスを使用しているときにTextプロパティをバインドする方法の詳細については、他の回答を参照してください。そうしないと、制限がトリガーされません。
バックスペースについては、 PreviewKeyDown イベントを確認してください
貼り付けコマンドの場合は、ApplicationCommands.Pasteにコマンドバインドを追加し、何も処理しない場合は引数を処理済みに設定します。
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Paste"
Executed="PasteExecuted" />
</Window.CommandBindings>
そして、コードビハインドでは:
private void PasteExecuted(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
}
これは、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
}
これは私にとってはかなりうまく機能します。ユーザーがコンテンツを変更したときに、テキストボックスの色を変更したかった。
以下の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;
}
}