User32.dll 的 SendMessage 方法返回错误的 ListViewGroup id

Posted

技术标签:

【中文标题】User32.dll 的 SendMessage 方法返回错误的 ListViewGroup id【英文标题】:User32.dll's SendMessage method returns wrong ListViewGroup id 【发布时间】:2013-04-17 07:34:51 【问题描述】:

我想处理组标题单击事件。我使用来自this post 的信息来实现我的目标。应用程序正确识别鼠标单击组标题,问题实际上是,如标题所述,SendMessage 方法返回的组 ID 对于某些组是错误的。

我的 ListView(我在上面测试过代码)如下所示:

Group 1
  Item 1.1
  Item 1.2
Group 2
  Item 2.1
  Item 2.2
Group 3
  Item 3.1

基本上,在我单击第二组或第三组之前,它都可以正常工作。单击组标题时,SendMethod 返回以下值:0 代表Group 1,2 代表Group 2,3 代表Group 3

这是 WndProc 方法的实现:

protected override void WndProc(ref Message m)
    
        bool passMessage = true;

        if (m.Msg == WM_RBUTTONDOWN)
        
            Point hitPoint = LParamToPoint(m.LParam);
            LVHITTESTINFO lvHitTestInfo = new LVHITTESTINFO();
            lvHitTestInfo.pt.x = hitPoint.X;
            lvHitTestInfo.pt.y = hitPoint.Y;

            int rtn = SendMessage(listView.Handle, LVM_SUBITEMHITTEST, -1, ref lvHitTestInfo);
            if (rtn != -1)
            
                if (((lvHitTestInfo.flags & LVHITTESTFLAGS.LVHT_EX_GROUP_HEADER) == LVHITTESTFLAGS.LVHT_EX_GROUP_HEADER))
                
                    passMessage = false;

                    string groupName;
                    if (rtn == listView.Groups.Count)
                        groupName = "default";
                    else
                        groupName = listView.Groups[rtn].Header;
                    GroupClicked.Invoke(listView, new ListViewInterceptorEventArgs(rtn, groupName));
                
            
        

        if (passMessage)
            base.WndProc(ref m);
    

我想显示与所选组相关的内容,所以我需要知道点击了哪一个。我正在使用 Windows 8。如果有人可以指导我找到解决方案,我将非常感激。如果您需要任何其他信息,请告诉我,我会为您提供。

附:在我的应用中,我动态添加组,如下所示:

                ListViewGroup contactsGroup = new ListViewGroup(group.id, group.name);
                contactsGroup.Name = group.id;
                contactsGroup.HeaderAlignment = HorizontalAlignment.Center;
                lvContacts.Groups.Add(contactsGroup);
                for (int i = 0; i < group.users.Count; i++)
                
                    ListViewItem lvi = new ListViewItem(group.users[i]);
                    lvi.SubItems.Add(group.userStatus[i] ? "ONLINE" : "offline");
                    lvi.Group = contactsGroup;
                    lvContacts.Items.Add(lvi);
                

同样的 WndProc 方法实现在另一个程序中工作得很好,我编写该程序只是为了测试这一点,但我通过设计器添加了组。

【问题讨论】:

这需要大量的工作才能以非常低的成功几率进行复制。如果您需要帮助调试此问题,则必须创建一个解决此问题的最小重现项目并将其发布到文件共享服务。 是的,我想你说得有道理。我想也许有人遇到了同样的问题并找到了解决方案,这样可以节省我几个小时,但我想我必须自己解决这个问题。还是谢谢! 我知道这是 3 岁,但我刚刚遇到了同样的事情。我找到了一种让它工作的方法,但它完全让我对正在发生的事情感到困惑。如果您首先创建 all ListViewGroup 对象,然后将它们添加到列表视图中 - 它可以工作......至少对我来说。如果有人愿意,我可以发布代码示例。 嗨,大卫。这是一个早已被遗忘的解决方案,但是当我有时间找到源代码,采用新的 VS/.NET 和其他东西时,我会检查它:) 感谢您的意见。 【参考方案1】:

2019 年 6 月:这仍然是一个微软显然尚未解决的问题!

但感谢 David Amey,我们找到了解决办法。 您首先需要创建所有组并将其添加到列表视图中

Dim MyLvg As ListViewGroup = New ListViewGroup With .Header = "MyGroup1", .Name = "MyGroup1"
MyLsv.Groups.Add(MyLvg)

只有在此之后您才能添加项目。


想通了,在这个阶段如果你从头开始声明一个新的 ListViewItem 并添加它是行不通的,但是在这里你需要通过你现有的 ListView 实例创建它。然后只需将您的 Lvi 链接到您的 Lsv 即可。

Dim MyLvi As ListViewItem = MyLsv.Items.Add("This is my new item")
MyLvi.Group = MyLvg

最后,让我补充一点,我已经测试了 6 种将 ListViewItems 链接到 ListViewGroups 的方法,并且一切正常

MyLvi.Group = MyLvg
MyLvi.Group = MyLsv.Groups(0)
MyLvi.Group = MyLsv.Groups("MyGroup1")

MyLvg.Items.Add(MyLvi)
MyLsv.Groups(0).Items.Add(MyLvi)
MyLsv.Groups("MyGroup1").Items.Add(MyLvi)

这似乎合乎逻辑,但我们仍然没有发现这些错误,所以我更愿意仔细检查。

使用这种创建和链接组和项目的方式肯定会确保您避免来自 LVHITTESTINFO 的“Bad Group Id”问题

【讨论】:

以上是关于User32.dll 的 SendMessage 方法返回错误的 ListViewGroup id的主要内容,如果未能解决你的问题,请参考以下文章

user32.dll SendMessage:以大写字符发送的字符串...但区分大小写的字符串

是否有从 USER32.DLL 导入所有内容的 C# 即用型类? [关闭]

Windows SendMessage()消息代码[关闭]

SendMessage 不适用于 InternetExplorer 对象

使用 PostMessage() 或 SendMessage() 发送大写字母

ring0 ShadowSSDTHook