How to Prevent Excessive Messages When Selecting Multiple Items in Virtual Listview With a Mouse?

234 Views Asked by At

I have been working on creating my own Virtual Listview control in Visual Basic 6. I have subclassed the SysListView32 class in a UserControl, and have been able to successfully code the control to add, delete, and even sort items. All of this works fast, as it should in a Virutal Listview control (LVS_OWNERDATA window style set). However, when I start a marquee selection of multiple items by click-dragging a mouse (LVS_SINGLESEL window style absent), the selection process is fairly slow, and gets slower as more items are selected going further down the list. This happens even with only 2 - 3 hundred items added to the list. The best sample amount to view the effect with, is about 500 items.

As I have been working on building the control, I have also added almost every conceivable message that a SysListView32 class would normally get, and every notification code that the UserControl should get, so that at the change of a DEBUGFLAG constant variable, I can use the Immediate pane in VB6 to tell me exactly what is going on. Upon further investigation into the messages being sent and received by the control, I noticed the NM_CUSTOMDRAW notification code is happening a lot more often than it should be, with item indices starting off with item '0', '1', '2' and so on in each new "wave" of selections, even when those items are not actually visible.

I have tried handling the NM_CUSTOMDRAW messages of those items that are not within view, by trying to send the CDRF_SKIPDEFAULT return value. Note that the first NM_CUSTOMDRAW notification does not store the relevant item index; you need to process the first notification with the CDRF_NOTIFYITEMDRAW value, in order to retrieve the item index of the item that is being re-painted.

Case NM_CUSTOMDRAW
    Dim NotifyLVCDraw As NMLVCUSTOMDRAW
    CopyMemory NotifyLVCDraw, ByVal lParam, 60
    Select Case NotifyLVCDraw.nmcd.dwDrawStage
    Case CDDS_PREPAINT
        If ICount Then
            IVBSubClass_WndProc = CDRF_NOTIFYITEMDRAW
            bHandled = True
        End If
    Case CDDS_ITEMPREPAINT
        Dim I As Long, J As Long
        I = SendMessageW(hUniListView, LVM_GETTOPINDEX, 0, ByVal 0&)
        J = SendMessageW(hUniListView, LVM_GETCOUNTPERPAGE, 0, ByVal 0&) + I
        If NotifyLVCDraw.nmcd.dwItemSpec >= I And NotifyLVCDraw.nmcd.dwItemSpec <= J Then
            'Item Back Colour / Text Colour code
        Else
            IVBSubClass_WndProc = CDRF_SKIPDEFAULT
        End If
        bHandled = True

However, this does not solve the problem. It seems that even if the items are not redrawn, the fact that these messages are being sent in the background is enough to slow down the selection of multiple items. There are even LVN_ODCACHEHINT notifications before each wave, that give a range of '0' to the last visible item index, when really they shouldn't be.

I shouldn't need to provide all of my code; I'm not doing anything overly fancy with my code, and it appears to be the default behaviour of the control when using LVS_OWNERDATA, so I doubt it would help solve the problem. I do suspect, however, that I will need to do something fancy to solve the problem.

I also had a look at this question, but reflection is going out of my area of knowledge, and I can't seem to find any message received by the subclassed window procedure relating to WM_REFLECT_NOTIFY.

Thanks in advance.

0

There are 0 best solutions below