Virtualize regression in .NET 11: Home and End typed in a text input jump the list to its first or last item

Đang mở
#70,554 2 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
55/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
csharp, javascript
Lĩnh vực
frontend

Hướng nghiên cứu

Start by reading Virtualize.ts and its handleJumpKeys keydown handler; the issue identifies this as the source of the regression and links its introduction to #64964. Reproduce with the supplied Blazor pages, especially an input inside a virtualized list, and compare Home and End behavior with .NET 10. Done when typing those keys in editable controls leaves the list position and focus intact while list navigation still works when the list itself has focus.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

area-blazor Regression
Is there an existing issue for this?
  • I have searched the existing issues
Describe the bug

.NET 11's Virtualize listens for keydown on its scroll container, or on document when the page itself scrolls, and treats every Home and End as a request to jump to the start or end of the list (handleJumpKeys in Virtualize.ts). It came with #64964 in 11.0-preview3; .NET 10 had no key handling in Virtualize.ts. It doesn't check where the key came from, so Home and End typed in a text input also jump the list instead of only moving the caret:

  • Input inside the list: the list jumps and the row being edited is virtualized away. With @key its input is removed and focus falls back to <body>. Without @key, as in the first page below, Blazor reuses the focused input for another item, so the caret ends up in a different row (Name 977 after End from Name 204).
  • List that scrolls with the page: End in any input on the page, such as a search box above the list, scrolls the page to the end of the list.

The handler also runs for keys a component has already handled. A list component that implements Home and End itself and calls preventDefault() still gets the jump on top of its own behaviour.

On .NET 10 these keys only move the caret. Lists with inputs in or around them are common: editable grids, filter rows in a sticky header, forms over long collections, search boxes. QuickGrid has it too: in a virtualized QuickGrid with a search box in ColumnOptions, like the column options example in the QuickGrid docs, Home and End typed in the search box jump the grid to its first or last row (third page below). We found this through MudBlazor's MudDataGrid (cell editing and the column filter row) and MudTable with text fields in rows.

Expected Behavior

As on .NET 10.0.15, Home and End in a text input move the caret and the list stays where it is.

Input inside the list (first page below), scrolled to 6000 px, after clicking the input of row 204:

Runtime End Home
.NET 10.0.15 stays at 6000 px, caret at end of "Name 204" stays at 6000 px, caret at start
.NET 11.0.0 jumps to the end (29700 px), focus in "Name 977" jumps to the top (0 px), focus in "Name 21"

Input above a list that scrolls with the page (second page below), after clicking the input: End leaves the page at 0 px on .NET 10.0.15 and scrolls it to 29279 px, the end of the list, on .NET 11.0.0.

QuickGrid search box in ColumnOptions (third page below), grid scrolled to 2768 px: End leaves the grid there on .NET 10.0.15 and jumps it to 31633 px (row 992) on .NET 11.0.0. Home jumps it to 0 px.

Returning early from handleJumpKeys when e.defaultPrevented is set or e.target is inside an input, textarea, select or editable contenteditable element makes .NET 11.0.0 match .NET 10 on all three pages. End and Home pressed while the list itself has focus, for example after clicking a QuickGrid cell, still jump. I tested that by rewriting blazor.web.js in flight; I have not built aspnetcore. The scroll keys that isUserScrollKey matches come through the same handler from inputs, so the check may belong before those as well.

Steps To Reproduce
  1. dotnet new blazor --interactivity Server --empty, and replace Components/Pages/Home.razor with the first page below.
  2. Scroll the list a little, click into one of the inputs, and press End or Home.
  3. The list jumps to its last or first item, and the caret is now in another row's input.
@page "/"
@rendermode InteractiveServer
@using Microsoft.AspNetCore.Components.Web.Virtualization

<p>@System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription</p>

<div style="height: 300px; overflow-y: auto; border: 1px solid #999;">
    <Virtualize Items="_names" Context="name" ItemSize="30">
        <div style="height: 30px;"><input value="@name" /></div>
    </Virtualize>
</div>

@code {
    private readonly List<string> _names = Enumerable.Range(0, 1000).Select(i => $"Name {i}").ToList();
}

For the page-scroll case, click into the input and press End:

@page "/window"
@rendermode InteractiveServer
@using Microsoft.AspNetCore.Components.Web.Virtualization

<p>@System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription</p>

<input value="Search text" />

<Virtualize Items="_names" Context="name" ItemSize="30">
    <div style="height: 30px;">@name</div>
</Virtualize>

@code {
    private readonly List<string> _names = Enumerable.Range(0, 1000).Select(i => $"Name {i}").ToList();
}

For QuickGrid, add the Microsoft.AspNetCore.Components.QuickGrid package, scroll the grid, open the Name column's options, click into the search box and press End or Home:

@page "/quickgrid-filter"
@rendermode InteractiveServer
@using Microsoft.AspNetCore.Components.QuickGrid

<p>@System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription</p>

<style>
    #grid { height: 300px; overflow-y: auto; }
    #grid table { min-width: 100%; }
    #grid thead { position: sticky; top: 0; background-color: #d8d8d8; z-index: 1; }
    #grid tr { height: 30px; }
</style>

<div id="grid">
    <QuickGrid Items="FilteredPeople" Virtualize="true" ItemSize="30">
        <PropertyColumn Property="@(p => p.Id)" />
        <PropertyColumn Property="@(p => p.Name)">
            <ColumnOptions>
                <input type="search" @bind="_filter" @bind:event="oninput" placeholder="Filter names..." />
            </ColumnOptions>
        </PropertyColumn>
    </QuickGrid>
</div>

@code {
    private record Person(int Id, string Name);

    private readonly List<Person> _people = Enumerable.Range(0, 1000).Select(i => new Person(i, $"Name {i}")).ToList();
    private string _filter = "";

    private IQueryable<Person> FilteredPeople => _people.Where(p => p.Name.Contains(_filter)).AsQueryable();
}

To compare with .NET 10, target net10.0;net11.0, replace <BasePath /> in App.razor with <base href="/" /> and add app.UseAntiforgery(); before app.MapStaticAssets();. For the QuickGrid page, reference QuickGrid 10.0.0 for net10.0 and 11.0.0 for net11.0.

Exceptions (if any)

None.

.NET Version

SDK 11.0.100, runtime 11.0.0 (ASP.NET Core 11.0.0). Compared with ASP.NET Core 10.0.15. Chrome 157 (headless, driven through the DevTools protocol), Windows 11.

Anything else?

handleJumpKeys is unchanged on main apart from the added interruptProgrammaticScroll() calls.

Ngôn ngữ chính
C#
Star
38.5k
Fork
11.6k
Merge trung bình
3 ngày 1 giờ
Pull request đã merge (30 ngày)
289

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của dotnet/aspnetcore

Tất cả issue của dotnet/aspnetcore

Issue tương tự

Thêm issue về C#

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.