2012-06-20 46 views
7

textbox.Undo();私は次のエラーを取得する:このような場合は、なぜTextChangedで元に戻すことができません

Cannot Undo or Redo while undo unit is open.

は今、私は理解して(それがアクティブに取り消し可能なイベントですので)が、ユーザが持っている場合はどのようなイベントを通じて、私は、テキストボックスの検証を実行し、変更を元に戻すことができます無効な文字を入力しましたか?

+0

代わりに行動を使用する必要があります。 – SepehrM

+0

SepehrM - 例を挙げることができますか? まだ妥当性検査をしたくないのに、この邪魔な例外メッセージがセッションを爆発させないようにしたいのですが?私は、ユーザーがちょっとしたビットをあまりにも速く入力するか、おそらくデータの塊をフィールドに貼り付けるときにこれを取得しています。検証することさえできません。 – Allen

答えて

6

UndoとTextChangedを使用する代わりに、PreviewTextInputDataObject.Pastingイベントを使用する必要があります。 PreviewTextInputイベントハンドラで、入力されたテキストが無効な文字の場合は、e.Handledをtrueに設定します。 Pastingイベントハンドラで、貼り付けられたテキストが無効な場合はe.CancelCommand()を呼び出します。ここで

は受け付けテキストボックスの一例であるだけ数字0と1:

XAML:

<Window x:Class="BinaryTextBox.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="133" Width="329"> 
    <StackPanel> 
     <TextBox x:Name="txtBinary" Width="100" Height="24" 
       PreviewTextInput="txtBinary_PreviewTextInput" 
       DataObject.Pasting="txtBinary_Pasting"/> 
    </StackPanel> 
</Window> 

コードの背後にある:

using System.Text.RegularExpressions; 
using System.Windows; 
using System.Windows.Input; 

namespace BinaryTextBox 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void txtBinary_PreviewTextInput(object sender, 
       TextCompositionEventArgs e) 
     { 
      e.Handled = e.Text != "0" && e.Text != "1"; 
     } 

     private void txtBinary_Pasting(object sender, DataObjectPastingEventArgs e) 
     { 
      if (!Regex.IsMatch(e.DataObject.GetData(typeof(string)).ToString(), "^[01]+$")) 
      { 
       e.CancelCommand(); 
      } 
     } 
    } 
} 
+0

ブリリアント - 完璧なソリューションありがとう –

+0

"貼り付け"ハンドラは、ドラッグアンドドロップを使用して文字を挿入している場合にも有効です。 – Mishax

+0

このアプローチの問題は、PreviewTextInputは、最終結果ではなく、入力中のものだけをプレビューすることです。これは、有効な値に関して考えられるすべての入力を説明する非常に複雑で維持不能なアルゴリズムを書く場合にのみ機能します。たとえば、小数点以下の欄では、マイナスまたはピリオドが適用されるときに検証を試みます。明らかに、それぞれのタイプは1つしか入力できませんが、すべてのタイプには入力できません。最良の解決策は、それがどのように入力されたかにかかわらず、最終結果を検証することです。残念なことにWPFはそのようなサポートを持っていません。 – Neolisk

3

コールから非同期的に元に戻しますTextChangedイベントハンドラから:

Dispatcher.BeginInvoke(new Action(() => tb.Undo())) 
+0

このソリューションと受け入れられた回答との比較はどのように行われますか? – InvalidBrainException

7

simbayのアプローチに答えるために、私は解雇されていると思います。

取り消し操作がまだTextBoxによって準備されているため、取り消しをTextChangedで呼び出すことはできません。他の時ではなく時々動作するように見えるので、イベントが通知されてから取り消し準備が完了するまでの間に競合状態が存在することが示唆されます。

しかし、ディスパッチャでUndoを呼び出すと、テキストボックスでUNDO準備が完了します。テキストの変更の結果を検証し、変更を保持するか元に戻すかを決定できます。これは最善の方法ではないかもしれませんが、テキストボックスにテキストの変更とペーストを吹き込み、例外を再現できませんでした。

「受け入れられた回答」は、無効な文字の入力や貼り付けを防ぎたい場合にのみ有効ですが、一般的にはTextBox入力の検証を頻繁に行い、最終的なテキスト値を確認する必要があります。プレビューイベントから最終テキストを識別することは容易ではありません。なぜなら、コントロールに関しては、まだ何も起こっていないからです。

テリブドの質問に答えるために、simbayの答えはより多くの状況でよりよく簡潔です。

tb.TextChanged =+ (sender, args) => 
{ 
    if(! MeetsMyExpectations(tb.Text)) 
     Dispatcher.BeginInvoke(new Action(() => tb.Undo())); 
} 

私は、テキストボックスの検証に野生の冒険をたくさん読んで、これは私が発見したと同じくらい簡単です。

関連する問題