我正在尝试创建一个简单的搜索输入控件,具有基于计时器的去抖功能。
Search.razor
:
<input type="search" placeholder="Search" @oninput=@((e) => SearchChanged(e)) />
@code {
[Parameter]
public EventCallback<string> OnSearchChanged { get; set; }
private System.Timers.Timer? _debounceTimer;
string Text = string.Empty;
public void SearchChanged(ChangeEventArgs e)
{
Text = e.Value == null ? string.Empty : e.Value.ToString()!;
// Debounce search
_debounceTimer?.Stop();
_debounceTimer?.Dispose();
_debounceTimer = new System.Timers.Timer(200);
_debounceTimer.Elapsed += DebounceTimerElapsed;
_debounceTimer.Enabled = true;
_debounceTimer.Start();
}
private void DebounceTimerElapsed(object? sender, EventArgs e)
{
_debounceTimer?.Dispose();
OnSearchChanged.InvokeAsync(Text); // <<< Dispatcher exception
}
}
我认为在这个组件中包含去抖动功能是有意义的,这样我就不必在每个父级上重复它。但我似乎无法使用 EventCallback 让父组件知道计时器已过。它抛出了臭名昭著的The current thread is not associated with the Dispatcher
异常。
Blazor University 上的此页面解释了非 UI 事件(例如Timer.Elapsed
在另一个线程上生成)。计时器确实是罪魁祸首,因为显然如果我OnSearchChanged.InvokeAsync()
直接从SearchChanged
. 但InvokeAsync()
在这种情况下似乎没有同步回 UI 线程。但我认为应该有一种简单的方法来完成这项工作。
有没有一种(简单)方法让父组件知道子组件中的计时器已过?