|
■No75882 (ni さん) に返信 > を同時にイベント処理したい、
MyTextBox は、System.Windows.Forms.TextBox を継承して作られています。
TextBox や RichTextBox は System.Windows.Forms.TextBoxBase を継承していますし、 TextBox は System.Windows.Forms.Control を継承しています。 そして Control は Object から継承されています。
…ここまでは認識されているでしょうか?
アプリ作成時に、まずは Form1 クラスが用意されるかと思いますが、 これも、System.Windows.Forms.Form クラスを継承したものですし、 その Form クラスは、System.Windows.Forms.Control を継承しています。
そして Control クラスには、TextChanged イベントや MouseDown イベントや Click イベントが 用意されているため、Control の派生クラスである Form や Form1、TextBox や MyTextBox も 同様にこれらのイベントを利用できるはずです;本来は。
にもかかわらず >> なぜ継承しているのに、イベントが正しく発生しないのか今現在わかりません。 という状態になるのであれば、イベントが発生しないというよりは、 コーディング上の問題により、 ・自作クラス MyTextBox が、イベントを発生させていない ・利用側となる Form1 で、そのイベントを受け取っていない のいずれかであろうと推察します。
> 魔界の仮面弁士 さんの例ではTextBox0、TextBox1、TextBox2、 > と3つ分のイベントをバラバラで回していらっしゃいますが、 一箇所で受け取りたいのであれば、 Private Sub TextBoxes_TextChanged(sender As Object, e As EventArgs) Handles TextBox0.TextChanged, TextBox1.TextChanged, TextBox2.TextChanged のように、Handles 句で対象イベントを列挙する方法があります。
ただし、Handles 句を使う場合には、WithEvents 変数も必要になります。 コントロールが 10 個あるなら、WithEvents 変数も10個必要です。
あるいは、「AddHandler ステートメント」を用いるのも良いでしょう。 これなら、WithEvents 変数を用意せずとも、複数のイベントをまとめて処理できます。 解除する場合は、ご存知のように「RemoveHandler」です。
Public Class Form1 Private Sub Test(sender As Object, e As EventArgs) MsgBox("クリック@" & sender.GetType().Name & "@" & sender.Name) End Sub
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load AddHandler Me.TextBox1.Click, AddressOf Me.Test AddHandler Me.Label1.Click, AddressOf Me.Test AddHandler Me.ListBox1.Click, AddressOf Me.Test AddHandler Me.Click, AddressOf Me.Test End Sub End Class
もし、 AddHandler Me.TextBox1.Click, AddressOf Me.Test AddHandler Me.TextBox1.Click, AddressOf Me.Test のように複数回に割り当てると、イベント通知も複数回発生するので注意して下さい。
>>標準のコンテキストメニューに対しての操作を、 >>NativeWindow クラスまたは TextBox クラスの >>WndProc メソッドで拾っている、ということでしょうか。 >> >>それとも、ContextMenuStrip プロパティを >>差し替えている、ということでしょうか。 > の辺りの意味が解りませんでした。
分かりにくくてすみません。 TextBox のコンテキストメニューは、通常、OS で用意されたものが使われますよね。
「ContextMenuStrip プロパティを差し替える」というのは、 ツールボックスからContextMenuStrip をフォームに貼り、それを TextBox の ContextMenuStrip プロパティに割り当てることで、標準のメニューではなく 自作のメニューにするということです。
そして「WndProc メソッド」の方は、じゃんぬさんの MyTextBox で使われている方法です。 『Protected Overrides Sub WndProc(ByRef m As Message)』の中で、 WM_PASTE メッセージを処理している部分がそれにあたります。
そして、継承せずに WndProc を処理する場合には、NativeWindow クラスを使えます。
たとえばこんな感じです。下記を実行すると、「コンテキストメニュー」や 「Ctrl+V」「Shift+Insert」を含むあらゆる貼り付け処理を事前に横取りできます。
-------------------------- Imports System.ComponentModel Public Class Form1 Private WithEvents sample As NativeWindowSample
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load sample = New NativeWindowSample(Me.TextBox1) End Sub
Private Sub sample_Pasting(sender As Object, e As CancelEventArgs) Handles sample.Pasting If MsgBox("貼り付けますか", vbQuestion Or vbOKCancel) = vbCancel Then e.Cancel = True End If End Sub
End Class
Public Class NativeWindowSample Inherits NativeWindow Private Owner As Form1 Public Event Pasting As CancelEventHandler
Public Sub New(owner As Control) MyBase.AssignHandle(owner.Handle) End Sub
Protected Overrides Sub WndProc(ByRef m As Message) 'Const WM_CUT = &H300 'Const WM_COPY = &H301 Const WM_PASTE = &H302 'Const WM_CONTEXTMENU = &H7B
Dim e As New CancelEventArgs(False) If m.Msg = WM_PASTE Then RaiseEvent Pasting(Me, e) End If If Not e.Cancel Then MyBase.WndProc(m) End If End Sub End Class --------------------------
> ご提案いただいたTextBoxBaseを取り入れて後、なぜかまったく TextBoxBase は利用しないでください。(継承関係の参考として提示しただけです。すみません) 通常は、TextBox あるいは MyTextBox をそのまま利用すれば OK です。
> TextBoxBaseでの処理が何か関係あるのでしょうか。 関係しないと思います。WithEvents 変数の扱いを間違えていたりはしませんか?
> 常に、最後のUndoが戻ってくる、右クリックコンテキストメニュー内容は > 本当にそっくりそのままメモ帳仕様を希望しております。 であれば無理に作りこまず、標準の Undo 動作を活かす方法を模索するのがよろしいかと。
> テキストボックスでいくつかの文字列がある時、フォーカスがなくとも > 【インターネットブラウザの様に右クリックでカーソルがポイント位置に移動する】 コンテキストメニューを無効にしてみましたが、その場合、右クリックや中クリックでは、 フォーカスの移動が行われないようですね。
とりあえず、こんな感じで如何でしょう。 WndProc メソッドを下記のように実装してみて下さい。
Select Case m.Msg Case WM_RBUTTONDOWN '&H204 Dim m2 = Message.Create(m.HWnd, m.Msg, m.WParam, m.LParam) m.Msg = WM_LBUTTONDOWN '&H201 MyBase.WndProc(m) MyBase.WndProc(m2) Return Case …
|