Virtualize regression in .NET 11: Home and End typed in a text input jump the list to its first or last item
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ả
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
@keyits 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 977after End fromName 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
dotnet new blazor --interactivity Server --empty, and replaceComponents/Pages/Home.razorwith the first page below.- Scroll the list a little, click into one of the inputs, and press End or Home.
- 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
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.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- 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.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của dotnet/aspnetcore
-
area-networking
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
dotnet/aspnetcore#70545 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area-infrastructure
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
dotnet/aspnetcore#70524 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[OpenTelemetry] Hosting replaces an Activity.DisplayName that the app set, when a route matchesĐang mởarea-hosting Regression
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
dotnet/aspnetcore#70516 · 1 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[SSE] ServerSentEventsResult.WrapEvents is missing [EnumeratorCancellation], so RequestAborted never reaches the app's generator on the IAsyncEnumerable<T> overloadCó thể đã có người làm @bharatprajapati-coder đã nhận 1 ngày trước. Đang mởarea-minimal
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
dotnet/aspnetcore#70419 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[Blazor] DefaultInMemoryCircuitPersistenceProvider never disposes the retention CancellationTokenSource when a persist is rejected at capacityCó thể đã có người làm @Vinoth2562000 đã nhận 1 ngày trước. Đang mởarea-blazor
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
dotnet/aspnetcore#70418 · 1 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của dotnet/aspnetcore
Issue tương tự
-
bug emitter:client:csharp
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
microsoft/typespec#12572 · 1 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
needs-area-label
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 2 ngày
-
AWS Lambda: KeyNotFoundException drops HTTP-triggered transactions when allowAllHeaders is disabledĐang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
newrelic/newrelic-dotnet-agent#3949 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 87/100
Maintainer thường phản hồi trong vòng 1 ngày
-
priority:P2
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 80/100