MudDataGrid INotifyCollectionChanged does not work in InteractiveServer rendermode
#10,973 创建于 2025年3月6日
仓库指标
- 星标
- (10,394 个星标)
- PR 合并指标
- (平均合并 6天 6小时) (30 天内合并 108 个 PR)
描述
Things to check
- I have searched the existing issues for this bug
- To rule out a caching problem I made sure the bug also happens in an incognito tab
Bug type
Component
Component name
MudDataGrid
What happened?
Using MudDataGrid in InteractiveServer render mode with Items being an ObservableCollection, will not result in the grid updating when items are added via another thread.
Note this does NOT happen in a web assembly project, which is why in the try.mudblazor.com you can see it working.
But if you have a project that is <Routes @rendermode="InteractiveServer" /> then it will throw an exception.
Also there is an additional bug, which is that MudDataGrid MUST have Groupable=true set for any INotifyCollectionChanged implementation to work, which is because this code is guarded by checking the Groupable property.
Expected behavior
INotifyCollectionChanged.CollectionChanged handler in MudDataGrid should InvokeAsync(..) and not require Groupable=true.
Reproduction link
https://try.mudblazor.com/snippet/mEQpYnuqCmwquNHf
Reproduction steps
@page "/"
@using System.Collections.ObjectModel
<PageTitle>Home</PageTitle>
<MudButton OnClick="Start">Start</MudButton>
<MudButton OnClick="Stop">Stop</MudButton>
<MudDataGrid Items="_items" Groupable="true">
<Columns>
<PropertyColumn Property="x => x.Age" />
</Columns>
</MudDataGrid>
@code {
private Task? _executeTask;
private CancellationTokenSource? _stoppingCts;
ObservableCollection<TestType> _items = new ObservableCollection<TestType>();
private async Task Start()
{
await Stop();
_stoppingCts = new CancellationTokenSource();
_executeTask = AddItemsAsync(_stoppingCts.Token);
}
private async Task Stop()
{
if (_executeTask is null) return;
_stoppingCts?.Cancel();
await _executeTask;
}
private async Task AddItemsAsync(CancellationToken cancellationToken)
{
while(!cancellationToken.IsCancellationRequested)
{
try
{
_items.Add(new TestType { Age = Random.Shared.Next(1, 100) });
await Task.Delay(2000, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);
}
catch(Exception ex)
{
//InvalidOperationException will be thrown here
}
}
}
public class TestType
{
public int Age { get; set; }
}
}
Relevant log output
System.InvalidOperationException: The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.
at Microsoft.AspNetCore.Components.Dispatcher.AssertAccess()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.RenderHandle.Render(RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
at MudBlazor.MudDataGrid`1.GroupItems(Boolean noStateChange)
at MudBlazor.MudDataGrid`1.<set_Items>b__278_0(Object s, NotifyCollectionChangedEventArgs e)
at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
at MudBlazorWebApp1.Components.Pages.Home.AddItemsAsync(CancellationToken cancellationToken) in C:\src\\MudBlazorWebApp1\Components\Pages\Home.razor:line 39
Version (bug)
8.3.0
Version (working)
No response
What browsers are you seeing the problem on?
Firefox
On which operating systems are you experiencing the issue?
Windows
Pull Request
- I would like to do a Pull Request
Code of Conduct
- I agree to follow this project's Code of Conduct