TextChangedイベントの発生原因の見分け方
通常TextBoxにおけるTextChangedイベントはユーザーからの入力 と、プログラム中でTextプロパティ等を変更した際の両方で発生します。 これを、どちらの原因で発生したTextChangedイベントかを見分ける方法を紹介します。
簡単な方法はフォーカスを調べる
最も簡単な方法はTextChangedイベントの第一引数であるsenderを通してTextBoxにフォーカスが 存在するかどうかを判断材料にする方法です。例えば、次のような場合に有効です。 フォーム上にTextBoxとButtonを配置して、Buttonを押下するとTextBoxの内容が変更されるという場合を考えてみます。 この場合、Buttonの押下によって発生したTextChangedイベントのsenderを調べてみれば、 TextBoxにフォーカスが無いことを知ることができ、判定できます。例えば以下のようなサンプルが考えられます。
{
if(((TextBox)sender).Focused == true)
MessageBox.Show("このTextChangedイベントはユーザーによる変更で発生しました。");
else
MessageBox.Show("このTextChangedイベントプログラム中での変更で発生しました。");
}
しかし、この方法は普遍的ではありません。上記のような特殊な場合には適用できますが、適用できない例もいくつか 存在します。例えば、TextChangedイベント内でTextプロパティ等を変更した際の判定です。このような場合に 対処するにはもっと抜本的な方法が必要です。
Textプロパティをオーバーライドするのは困難
最も最良な方法はTextBoxなどを継承してTextプロパティ等のTextBox内のテキストを変更するプロパティ及び メソッド内でフラグを立て、TextChangedイベントに反映させる方法でしょう。しかし、TextプロパティはContorlクラスに実装されており、 その中でOnTextChanged()(TextChangedイベントを発生させるprotectedメソッド)が呼び出されています。 これでは、ControlクラスからTextBoxBaseを経て作られているTextBoxクラスを継承してTextプロパティを変更することは 難しいでしょう。又、Contorolクラスを変更して新たにTextBoxBaseやTextBoxを実装しなおすのは非常に骨が折れます。
WndPrc()をオーバーライドしてメッセージをキャッチ
ひとつの例として以下のような方法が考えられます。一般的にTextBoxのテキスト内容を変更したい時には、 Text、SelectedText、Lines、AppendText()等のプロパティ及びメソッドを使用することになると思いますが、 これらのプロパティやメソッドを調べてみると、SetWindowText()というAPI関数か EM_REPLACESELというメッセージの送信によってテキストを変更していることが分かります。 また、SetWindowText()はWM_SETTEXTというメッセージを送信します。 そこで、TextBoxを継承してWndPrc()をオーバーライドします。そしてその中でこれらのメッセージを監視して それが送信されたときにフラグを立ててやればいいことになります。実際には次のようなコードになるでしょう。
{
if(m.Msg == WM_SETTEXT || m.Msg == EM_REPLACESEL)
{
blnIsUserChange = false;
}
base.WndProc (ref m);
}
blnIsUserChangeはユーザーの変更によるものかどうかを表す、privateフィールドで、宣言時にtureで初期化しておきます。 そして、TextChangedEventArgsなどを次のように定義しておきます。
{
private bool blnIsUserChanged;
public TextChangedEventArgs(bool isUserChanged)
{
this.blnIsUserChanged = isUserChanged;
}
public bool IsUserChanged
{
get
{
return blnIsUserChanged;
}
}
}
あとはイベントを追加してOnTextChanged()をオーバーライドして、その中からイベントを呼び出します。
public new event TextChangedEventHandler TextChanged;
{
if(this.TextChanged != null)
TextChanged(this, new TextChangedEventArgs(blnIsUserChange));
blnIsUserChange = true;
}
実際にFormから使用するときには以下のようにします。
{
if(e.IsUserChanged)
MessageBox.Show("このTextChangedはユーザーによる変更で発生");
else
MessageBox.Show("このTextChangedはプログラム中での変更で発生");
}