DOBON.NET DOBON.NETプログラミング掲示板過去ログ

コントロールのイベント無効化について

環境/言語:[Windows2000 VB.NET .NET Framework 1.0]
分類:[.NET]

 VB.NETでアプリケーションを開発していますが、
例えばTextBoxで、
ユーザがキーボードなのでテキストを変更した場合にはTextChangeイベントが発生し、
プログラムでテキストを変更した場合はTextChangeイベントが発生しないようにしたい
といった、
 ・ユーザーがアクションを起こした場合にだけ処理を行い。
 ・プログラムでアクションを起こした場合は処理を行わない。
ようにするには通常どのようにするものなのでしょうか?
 私には「フラグを立てて、Handles付き関数の最初にフラグがOnなら処理しない」
というやり方しか思いつきません。
 コントロールのイベント自体を無効化するやりかたはないものでしょうか?
こんばんは、Mu-さん。ピラルクです。

一時的にイベントを無効化するならば、

RemoveHandler TextBox1.TextChanged, AddressOf TextBox1_TextChanged
TextBox1.Text = "Changed by PG"
AddHandler TextBox1.TextChanged, AddressOf TextBox1_TextChanged

というAddHandler/RemoveHandlerが使えますが、
プログラムから変更するところで全て行うことになるので
面倒そうですね。
もう一歩進めて、TextBoxを継承したClassで、
「プログラムから変更する」用のPropertyを作って内部で
事前・事後処理を入れれば1行でOKになりますが。
TextBox1.Text_SetFromPG = "xxx"

プログラムから変更する時は必ずButtonをClickした時とか
で、TextBoxにフォーカスがあたっていることはありえない
と決め付けれるなら、

Private Sub TextBox1_TextChanged(...
If Me.ActiveControl Is TextBox1 Then
Console.WriteLine("Changed by User")
Else
Console.WriteLine("Changed by PG")
End If
End Sub

と、Event内でActiveControlで見分けるのが、手っ取り早い
かも。
(#Key系のEventはPopupからの貼り付けで悩むのでNGですね)

もともとフラグで区別が必要な感じなので、フラグもそう悪
くはないと思いますが。(実装漏れがいやらしい?)

TextBox1.ModifiedというHelpを見てもよくわからない(^^;
プロパティもありますね。上の
If Me.ActiveControl Is TextBox1 Then

If TextBox1.Modified Then
に変えても一見上手く動いてくれてます。(一度調べてみて下さい)
Dim t As TextBox = Me.TextBox1
Me.TextBox1 = Nothing
t.Text = Now.ToString
Me.TextBox1 = t
t = Nothing

イベントハンドルしてない変数に一時的に待避させとくのはどうでしょう。
レスありがとうございます。

ピラルクさん、TextBoxを継承したClassを利用するというアイデアは良いと思います。
Class内でフラグを立てるとしても、Classならコードは1箇所ですむので
問題ありません。TextBox使用個所が多い場合はかえってすっきりすると思います。

CCCPさん、オブジェクト変数を代入した場合はイベントが発生しないんですね!
知りませんでした。

余談ですが、AddHandlerでイベントを対応付けた場合、イベントが複数回発生しませんか?
コンボボックスのSelectedIndexChangeイベントをAddHandlerで対応つけた場合
一回のIndexChangeで2回イベントが発生しました。
解決済み!
2004/02/20(Fri) 10:12:26 編集(投稿者)

> CCCPさん、オブジェクト変数を代入した場合はイベントが発生しないんですね!
> 知りませんでした。

他の方が、この文面を読まれたときに誤解されるといけないので念のため書いておくと、

1.WithEvents付きで宣言された変数TextBox1のインスタンス(Aとします)
の参照をローカルの変数tにコピーしておきます。(インスタンスAを待避するため)

2.変数TextBox1をNothingにします。

3.変数TextBox1をNothingにしたので、変数TextBox1を介してイベントを扱っている
イベントプロシージャ(Handles TextBox1.イベント名を付けているプロシージャ)は
コールされなくなります。
(Nothingにセットしたことで変数TextBox1とインスタンスAが無関係になったためです)

4.インスタンスAからのイベントの通知を受け取らずに行いたい処理を記述します。

5.待避しておいたtをTextBox1にセットすることで元通りにします。

という流れです。

内部的にやっていることとしては、 No2603 のピラルクさんの投稿の

> RemoveHandler TextBox1.TextChanged, AddressOf TextBox1_TextChanged
> TextBox1.Text = "Changed by PG"
> AddHandler TextBox1.TextChanged, AddressOf TextBox1_TextChanged

これと同じような処理が行われていると思われます。
ただし、TextChangedイベントの関連付け解除(RemoveHandler )→関連付け(AddHandler)だけでなく、
TextBox1に対してハンドルしているすべてのイベントがRemoveHandler →AddHandlerされているような感じになると思います。

> 余談ですが、AddHandlerでイベントを対応付けた場合、イベントが複数回発生しませんか?

No2603 のようにRemoveHandlerで関連付け解除しても、そのようになりますか?
だとすれば、WithEventsの内部機構の作りとして、RemoveHandler/AddHandlerとの
併用はできない仕様なのかもしれません。

> コンボボックスのSelectedIndexChangeイベントをAddHandlerで対応つけた場合
> 一回のIndexChangeで2回イベントが発生しました。

それって、WithEvents&HandlesとAddHandlerを両方やってしまってるだけでは?
この場合、2回イベントの関連付けをやっているのでイベントの通知も2回上がります。

DOBON.NET | プログラミング道 | プログラミング掲示板