Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ListBox.IndexFromPoint should be Int32 but currently is Int16 #12637

Closed
Liv-Goh opened this issue Dec 13, 2024 · 6 comments
Closed

ListBox.IndexFromPoint should be Int32 but currently is Int16 #12637

Liv-Goh opened this issue Dec 13, 2024 · 6 comments
Labels
🪲 bug Product bug (most likely)

Comments

@Liv-Goh
Copy link
Contributor

Liv-Goh commented Dec 13, 2024

.NET version

.NET 10

Did it work in .NET Framework?

No

Did it work in any of the earlier releases of .NET Core or .NET 5+?

No, this issue can repro on .NET 6.0

Issue description

According to documentation, List Box IndexFromPoint should be Int32 but in tested result is Int16 because the max value is 65535.

Current behavior

  • The IndexFromPoint is currently Int16, the max value is 65535
  • If hold and drag the scroll bar exceeding item 65535, the top index will switch to the previous set of IndexFromPoint position
IndexFromPointIssue.mp4

Expected behavior

  • The IndexFromPoint should be Int32 based on the documentation, the max value should be 4,294,967,295
  • If hold and drag the scroll bar exceeding item 65535, the top index should not be affected

Steps to reproduce

  1. Extract and run IndexFromPointIssue.zip
  2. Try to click on the item to check the index
  3. Click 65535 button to go to 65535th item
  4. Click the 65536 item and observe its index
  5. Hold and drag the cursor to bottom and observe the listbox behavior

More Info

This issue is from feedback ticket FeedbackTicket 2318021 Visual Studio 2022 Visual Basic Listbox bug

@Liv-Goh Liv-Goh added the untriaged The team needs to look at this issue in the next triage label Dec 13, 2024
@elachlan elachlan added the 🪲 bug Product bug (most likely) label Dec 14, 2024
@KalleOlaviNiemitalo
Copy link

ListBox.IndexFromPoint uses the LB_ITEMFROMPOINT message for which this is a documented limitation:

The return value contains the index of the nearest item in the LOWORD.

I suppose it would be possible to work around the limitation by making ListBox.IndexFromPoint use other messages. For example, send LB_GETITEMRECT and check whether the rectangle is close enough to the specified point; if it isn’t, then do a binary search with more LB_GETITEMRECT messages.

Alternatively, change the application to use the ListView control.

@elachlan
Copy link
Contributor

ChatGPT suggestion based on @KalleOlaviNiemitalo

/// <summary>
///  Retrieves the index of the item at the given coordinates, without being limited to 65,535 items.
/// </summary>
public int IndexFromPoint(int x, int y)
{
    // Check if the point is within the client rectangle
    PInvokeCore.GetClientRect(this, out RECT clientRect);
    if (!(clientRect.left <= x && x < clientRect.right && clientRect.top <= y && y < clientRect.bottom))
    {
        return NoMatches; // Point is outside the client area
    }

    // Get the total number of items in the list box
    int itemCount = (int)PInvokeCore.SendMessage(this, PInvoke.LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
    if (itemCount <= 0)
    {
        return NoMatches; // No items in the list box
    }

    // Binary search for the item at the specified point
    int low = 0;
    int high = itemCount - 1;

    while (low <= high)
    {
        int mid = low + (high - low) / 2;

        // Get the rectangle of the item at index `mid`
        RECT itemRect;
        if (PInvokeCore.SendMessage(this, PInvoke.LB_GETITEMRECT, (IntPtr)mid, out itemRect) == IntPtr.Zero)
        {
            return NoMatches; // Failed to retrieve item rectangle
        }

        if (itemRect.top <= y && y < itemRect.bottom)
        {
            // Found the item containing the point
            return mid;
        }
        else if (y < itemRect.top)
        {
            // Point is above this item
            high = mid - 1;
        }
        else
        {
            // Point is below this item
            low = mid + 1;
        }
    }

    return NoMatches; // No matching item found
}

@KalleOlaviNiemitalo
Copy link

KalleOlaviNiemitalo commented Dec 16, 2024

If LB_GETCOUNT shows that the list box has so few items that no overflow is possible, then I think ListBox.IndexFromPoint can keep using LB_ITEMFROMPOINT as before. That strategy would minimise the compatibility risk.

@Tanya-Solyanik
Copy link
Member

This is a limitation of the underlying native control - https://learn.microsoft.com/en-us/windows/win32/controls/lb-setcount

@dotnet-policy-service dotnet-policy-service bot removed the untriaged The team needs to look at this issue in the next triage label Dec 19, 2024
@KalleOlaviNiemitalo
Copy link

According to the LB_SETCOUNT page, the 32767-item limit applies to "Windows 95/Windows 98/Windows Millennium Edition (Windows Me)". .NET doesn't even run on those operating systems any more so their problems should not prevent this from being fixed.

@Appenzeller-mbz
Copy link

I have submitted the same problem several days ago. It was taken into consideration and flushed here (as already submitted). And here, as I see, it is flushed by MS further into a drain. Regardless of it being an obvious and irritating bug left from jolly Int16 days. It is not a first case of me submitting something and MS disdaining me and disregarding the problem. Possibly, some day, when hell freezes...

Meanwhile, I used a standalone vertical scrollbar to mask the false one, and used Topindex (which is Long) and adding 65536 several times to substitute for Indexfrompoint.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🪲 bug Product bug (most likely)
Projects
None yet
Development

No branches or pull requests

5 participants