Rubrik: Verschiedenes / Sonstiges | VB-Versionen: VB.NET | 09.10.06 |
SubClassing mit VB.NET 2005 Dieser Tipp zeigt, wie man unter VB.NET Windows-Nachrichten abhorcht und selbst darauf reagieren, um bspw. das Kontextmenü einer TextBox zu deaktivieren etc. | ||
Autor: Roland Wutzke | Bewertung: | Views: 17.772 |
www.vb-power.net | System: WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 | Beispielprojekt auf CD |
Alle Windows-Objekte kommunizieren untereinander mit so genannten "Messages" (Nachrichten). Ändert ein Anwender bspw. mit der Maus die Größe eines Formulars, so schickt Windows eine Nachricht an dieses Formular (Achtung Formular - Du wurdest in der Größe verändert. Zeichne dich neu!). In VB.Net werden solche Nachrichten (teilweise) als Ereignisse zur Verfügung gestellt, z.B. wird Form_Resize bei der Änderung der Größe eines Formulars aufgerufen.
Oder aber der Anwender klickt mit der rechten Maustaste in eine TextBox, so wird das Kontextmenü aufgerufen. Auch hierzu schickt Windows eine Nachricht an die TextBox. Dabei wird das Ereignis "MouseUp" gefeuert, doch leider gibt es kein Ereignis für die Anzeige des Kontextmenü. Somit kann die Anzeige des Kontextmenü nicht unterbunden werden.
Und genau hier kommt unsere Klasse clsSubClass ins Spiel.
Unter SubClassing versteht man eine Technik, bei der die Messages von Windows an die eigene Verarbeitung (in unserm Fall die Klasse clsSubClass) umgeleitet werden, bevor man sie an das eigentliche Ziel (i.d.R. ein Steuerelement) weiterreicht. So kann man auf Nachrichten reagieren, und auch diese modifizieren, die eigentlich nicht von VB.Net unterstützt werden.
ACHTUNG: Der Umgang mit SubClassing und das Verändern von Nachrichten kann zu ungewollten Effekten mit der IDE führen. Sie sollten daher vor jedem Start der Anwendung unbedingt Ihren Quellcode speichern.
In unserem Demoprojekt zeigen wir Ihnen, wie bei TextBoxen das Kontextmenü abgeschaltet, und "Cut", "Copy", und "Paste" unterbunden wird. Weiterhin beinhaltet das Demoprojekt eine Auflistung von über 170 Windows-Messages im Klartext.
Hier der Code der Klasse clsSubClass:
''' <summary> ''' Stellt SubClassing für Steuerelemente mit einem Handle zur Verfügung. ''' </summary> ''' <remarks> ''' clsSubClass - VB.Net 2005 Klassenmodul ''' ====================================== ''' Diese Klasse stellt Subclassing Methoden für Steuerelemente zur Verfügung, ''' die über ein Windows-Handle verfügen. Dabei wird die Windows Message, die ''' an ein Steuerelement gesendet wird, über die Klasse umgeleitet und an die ''' aufrufende Form über den Event "WinProc" weitergegeben. ''' ''' Oktober 2006 - VB-Power.net ''' http://www.vb-power.net ''' </remarks> Public Class clsSubClass Private iList As New List(Of SubClassItem) Public Event WinProc(ByVal Index As Integer, ByVal Key As String, ByRef m As Message) ''' <summary> ''' Datenklasse: Speichert das Handle und den Key eines Steuerelements ''' </summary> Private Class SubClassItem Inherits System.Windows.Forms.NativeWindow Public m_Key As String Public Event WinProc(ByVal sender As SubClassItem, ByRef m As Message) Public Sub New(ByVal Handle As IntPtr, ByVal Key As String) MyBase.AssignHandle(Handle) m_Key = Key End Sub Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message) RaiseEvent WinProc(Me, m) MyBase.WndProc(m) End Sub End Class ''' <summary> ''' Fügt ein Steuerelement, dass gesubclassed werden soll, der Liste hinzu. ''' </summary> ''' <param name="Handle">Das Windows Handle des Steuerelements</param> ''' <param name="Key">Ein Key, der das Steuerelment repräsentiert</param> Public Sub Add(ByVal Handle As IntPtr, ByVal Key As String) Dim c As New SubClassItem(Handle, Key) AddHandler c.WinProc, AddressOf ItemWinProc iList.Add(c) End Sub Private Sub ItemWinProc(ByVal sender As SubClassItem, ByRef m As Message) RaiseEvent WinProc(iList.IndexOf(sender), sender.m_Key, m) End Sub End Class
Die Klasse ist so angelegt, dass sie beliebig viele Steuerelemente, die ein Windows-Handle besitzen, aufnehmen kann. Über das Klassen-Event WinProc werden die Nachrichten der Steuerelemente an die aufrufende Form umgeleitet. Dabei wird der Key mit an die Form übergeben, so dass eine einfache Weiterverarbeitung möglich ist.
Beispiel: Kontextmenü einer TextBox deaktivieren
Das Deaktivieren des Kontextmenü einer TextBox lässt sich mit Hilfe der SubClassing-Klasse wie folgt realisieren:
Public Class Form1 ' Klasse mit Ereignis instanzieren Private WithEvents mySubClass As New clsSubClass Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' Steuerelemente an die Klasse übergeben, ' die gesubclassed werden sollen. With mySubClass .Add(TextBox1.Handle, "TextBox1") End With End Sub ' Der Event aus der Klasse clsSubClass Private Sub mySubClass_WinProc(ByVal Index As Integer, _ ByVal Key As String, _ ByRef m As System.Windows.Forms.Message) Handles mySubClass.WinProc Select Case Key Case "TextBox1" ' TextBox1 - Kontextmenü unterdrücken If m.Msg = WM_MSGType.WM_CONTEXTMENU Then ' Nachricht terminieren m.Msg = 0 End If End Select End Sub End Class
Erfahrenen VB6 Programmierer unter Ihnen werden feststellen, wie einfach SubClassing unter VB.Net geworden ist. Keine API-Calls und Module mehr...
Viel Spaß...
Roland Wutzke