Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Subclassing in .NET - The pure .NET way

0.00/5 (No votes)
22 Nov 2002 1  
Capturing the Windows Messages for Windows Forms Controls

Introduction

If you are a Visual Basic 6 programmer then you are obviously aware of the sub-classing power. My article demonstrates the same thing for .NET. If you are a C# programmer, then you can easily change this code to fit into a C# Project. This project demonstrates how can you use the .NET way to subclass any control. This is the pure .NET way.

Using the code

Actually, you do not have to much to subclass your controls. What you have to do, is to create a class which should inherit from System.Windows.Forms.NativeWindow class. This class, as the name says, is the base class of a window. Using this class, you can use a function named AssignHandle which takes one parameter, the HWND of the object (control). And finally, you have to override a method named WndProc (method of NativeWindow Class). If you see the complete listing, then it will be clearer.

Imports System.Windows.Forms

Namespace theAngrycodeR
    'To Subclass any Control, You need to Inherit From 
    'NativeWindow Class

    Public Class SubClassing
        Inherits System.Windows.Forms.NativeWindow

        'Event Declaration. This event will be raised when any  
        'Message will be posted to the Control
        Public Event CallBackProc(ByRef m As Message)

        'Flag which indicates that either Event should be 
        'raised or not
        Private m_Subclassed As Boolean = False

        'During Creation of Object of this class, Pass the Handle 
        'of Control which you want to SubClass
        Public Sub New(ByVal handle As IntPtr)
            MyBase.AssignHandle(handle)
        End Sub

        'Terminate The SubClassing
        'There is no need to Create this Method. Cuz, 
        'when you will create the Object
        'Of this class, You will have the Method Named ReleaseHandle.
        'Just call that as you can see in this Sub

        'Public Sub RemoveHandle()
        '    MyBase.ReleaseHandle()
        'End Sub

        'To Enable or Disable Receiving Messages
        Public Property SubClass() As Boolean
            Get
                Return m_Subclassed
            End Get
            Set(ByVal Value As Boolean)
                m_Subclassed = Value
            End Set
        End Property

        Protected Overrides Sub WndProc(ByRef m As Message)
            If m_Subclassed Then 'If Subclassing is Enabled 
                RaiseEvent CallBackProc(m) 'then RaiseEvent
            End If
            MyBase.WndProc(m)
        End Sub

        Protected Overrides Sub Finalize()
            MyBase.Finalize()
        End Sub
    End Class

End Namespace

OK, you have prepared your class. Now come back in your form's code to use it. In the demo project, I used two command buttons and one text-box. And wrote the following code.

    Private Const WM_CLOSE As System.Int32 = &H10
    Private Const WM_QUERYENDSESSION As System.Int32 = &H11
    Private Const SC_CLOSE As System.Int32 = &HF060&
    Private Const WM_SYSCOMMAND As System.Int32 = &H112
    Private Const WM_KEYDOWN As System.Int32 = &H100
    Private Const WM_DESTROY As System.Int32 = &H2
    Private Const SC_MAXIMIZE As System.Int32 = &HF030
    Private Const SC_MINIMIZE As System.Int32 = &HF020
    Private Const SC_RESTORE As System.Int32 = &HF120

    'The Object of Subclassing to SubClass any Control
    Dim WithEvents abc As theAngrycodeR.SubClassing


#Region "Subclassing Current Form Only"
    'If you want to Subclass the Current Form only, 
    'then just remove these Comments 
    'You can not SubClass any Control using this method

    Protected Overrides Sub WndProc(ByRef m As Message)
        Select Case m.Msg
            'If from Meny Close Is Selected then
            Case Is = WM_SYSCOMMAND
                Select Case m.WParam.ToInt32
                    Case Is = SC_CLOSE
                        MsgBox("Closing")
                    Case Is = SC_MAXIMIZE
                        MsgBox("Maximize")
                    Case Is = SC_RESTORE
                        MsgBox("Restore")
                End Select

                Case Is = WM_DESTROY
                        MsgBox("Destroy")
            Case Is = WM_CLOSE
                MsgBox("Close")

            Case Is = WM_KEYDOWN
                MsgBox(m.HWnd.ToString)
                'MsgBox("Key Down : Virtual Code : " & m.HWnd.ToInt32 
                '& vbCrLf & "Key Data : " & m.LParam.ToInt32)
        End Select

                MyBase.WndProc(m)

    End Sub
#End Region

    Private Sub frmMain_Load(ByVal sender As System.Object, 
            ByVal e As System.EventArgs) Handles MyBase.Load
        abc = New theAngrycodeR.SubClassing(Button1.Handle)
        abc.SubClass = True
    End Sub

    Private Sub abc_CallBackProc(ByRef m As System.Windows.Forms.Message) 
            Handles abc.CallBackProc
        Const WM_MOUSELEAVE = &H2A3
        Const WM_MOUSEMOVE = &H200
        Const WM_MOUSEHOVER = &H2A1

        Select Case m.Msg
            Case WM_MOUSELEAVE
                TextBox1.Text += "Message Mouse Leave" & vbCrLf
            Case WM_MOUSEMOVE
                TextBox1.Text += "Message Mouse Moved" & vbCrLf
            Case WM_MOUSEHOVER
                TextBox1.Text += "Message Mouse Hover" & vbCrLf
        End Select
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, 
            ByVal e As System.EventArgs) Handles Button2.Click
        abc.ReleaseHandle()
    End Sub

Note that if you want to filter messages for the current form, then you can just write the code inside the WndProc method which is declared as Protected Overrides Sub WndProc ( ByRef m As Message ). For getting the messages for other windows, you can use the same code written above. The sample project is attached with this article. You can check this out and comment too.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here