65.9K
CodeProject 正在变化。 阅读更多。
Home

禁用ListView报表模式下的列调整大小

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.94/5 (9投票s)

2006 年 3 月 13 日

CPOL

3分钟阅读

viewsIcon

77541

本文介绍了如何使用 NativeWindow 对象来控制 ListView 的列标题的消息处理。 这允许程序员拦截消息并阻止或响应诸如列调整大小之类的事情。

引言

我最近的任务是想办法在 ListView 控件中禁用列调整大小。 在 Google 搜索中寻找线索,阅读文档以及进行一些试验和错误后,我终于弄清楚了如何做到这一点。 解决方案很简单、优雅,并且可以用作使用相同技术处理 ListView 控件的其他事情的基础。

背景

ListView 控件置于报告模式时,一个附加的子窗口将添加到控件中以容纳列标题。 此子窗口的 Windows 类是 SysHeader32 类。 遗憾的是,Microsoft 似乎忽略了在 .NET Framework 中公开此控件的包装器,并且没有提供简单的访问方法。

最终,这意味着大量 Windows 消息正在发送到您的 ListView 控件的 SysHeader32 窗口,该窗口不会为您的控件触发任何事件,并且您无法响应。

解决方案

解决方案是一个三步过程

  1. 获取 ListViewSysHeader32 子窗口的 Windows 句柄。
  2. 使用 Windows 句柄以某种方式接管其窗口的消息处理。
  3. 编写代码以响应感兴趣的消息以完成我们的目标。

步骤 1

第一步很简单。 还记得 Win32 API 调用的美好时光吗? 那么...它们在 Visual Basic .NET 中的工作方式与在 VB6 中一样好。 将以下声明放入可由你的窗体加载事件访问的范围内

Private Declare Function GetWindow Lib "user32" Alias "GetWindow" _
       (ByVal hwnd As IntPtr, ByVal wCmd As Integer) As IntPtr
Private Const GW_CHILD As Integer = 5
Dim SysHdr32Handle As IntPtr

并在您的窗体加载事件中,添加以下内容

SysHdr32Handle = GetWindow(ListView1.Handle, GW_CHILD)

上面的代码假定您已经创建了一个窗体窗口并在其上绘制了一个 ListView 控件。 由于 ListView 控件只有一个子窗口(SysHeader32 窗口),我们可以放心,因为这个调用将获得其 Windows 句柄。

第二步

现在我们需要一种方法来拦截发送到子窗口的消息。 幸运的是,.NET Framework 类库包含一个专门为此目的设计的类 - NativeWindow 类。 该类的 MSDN 帮助描述如下:

提供对窗口句柄和窗口过程的低级封装。

要使用该类,我们需要创建一个继承 NativeWindow 类的新类,以便我们可以覆盖 WndProc 消息处理函数以执行我们想要的操作。 将以下类定义添加到您的窗体代码

Private Class ListViewHeader
    Inherits System.Windows.Forms.NativeWindow
    Private ptrHWnd As IntPtr

    Protected Overrides Sub WndProc(ByRef m As _
                        System.Windows.Forms.Message)
        ' We'll add this in step 3


        MyBase.WndProc(m)
    End Sub

    Protected Overrides Sub Finalize()
        Me.ReleaseHandle()
        MyBase.Finalize()
    End Sub

    Public Sub New(ByVal ControlHandle As IntPtr)
        ptrHWnd = ControlHandle
        Me.AssignHandle(ptrHWnd)
    End Sub
End Class

当然,我们需要一个全局的窗体变量声明来使用,并且我们需要初始化我们的类实例。 将以下声明放入您的窗体类声明中

Private ListViewHeader1 As ListViewHeader

然后将以下代码行添加到您的窗体加载事件中

SysHdr32Handle = _
  GetWindow(ListView1.Handle, GW_CHILD) ' <-- added this in step 1

ListViewHeader1 = New ListViewHeader(SysHdr32Handle)

步骤 3

现在我们有了一种接收消息的方法,我们可以添加代码来处理它们。 在这个简单的例子中,我们将拦截 WM_SETCURSORWM_LBUTTONDOWN 消息并将它们丢弃,以防止用户看到调整列大小的光标以及能够调整列的大小。 如下修改我们的 ListViewHeader 类的 WndProc 方法

Protected Overrides Sub WndProc(ByRef m _
          As System.Windows.Forms.Message)
    Select Case m.Msg
        Case Is = &H20  ' WM_SETCURSOR

            m.Msg = 0
        Case Is = &H201  ' WM_LBUTTONDOWN

            m.Msg = 0
    End Select

    MyBase.WndProc(m)
End Sub

结论

上面的示例提供了一种获取这些 SysHeader32 消息句柄的基本方法。 因此,该示例相当粗糙。 例如,如果您想禁用两个 ListView 控件的列调整大小,该怎么办? 按照上面编写的方式,您将不得不创建两个不同的类。 一个健壮的实现将向类定义添加事件并在 WndProc 方法中收到 Windows 消息时触发它们,从而允许类实例的创建者处理它们。 但是,目前,这将帮助你入门。

© . All rights reserved.