如何在Blazor中向事件(OnInput)添加延迟?
例如,如果用户正在文本字段中键入,并且希望等到用户完成键入时再进行键入。
模板:3.0.0-预览8.19405.7
代码:
@page "/"
<input type="text" @bind="Data" @oninput="OnInputHandler"/>
<p>@Data</p>
@code {
public string Data { get; set; }
public void OnInputHandler(UIChangeEventArgs e)
{
Data = e.Value.ToString();
}
}发布于 2019-08-18 15:24:26
解决方案:
你的问题没有单一的解决办法。下面的代码只是一种方法。看一看,并使其适应您的需求。代码在每个keyup上重置一个定时器,只有最后一个计时器才会引发OnUserFinish事件。记住通过实现IDisposable来释放计时器
@using System.Timers;
@implements IDisposable;
<input type="text" @bind="Data" @bind:event="oninput"
@onkeyup="@ResetTimer"/>
<p >UI Data: @Data
<br>Backend Data: @DataFromBackend</p>
@code {
public string Data { get; set; } = string.Empty;
public string DataFromBackend { get; set; } = string.Empty;
private Timer aTimer = default!;
protected override void OnInitialized()
{
aTimer = new Timer(1000);
aTimer.Elapsed += OnUserFinish;
aTimer.AutoReset = false;
}
void ResetTimer(KeyboardEventArgs e)
{
aTimer.Stop();
aTimer.Start();
}
private async void OnUserFinish(Object? source, ElapsedEventArgs e)
{
// https://stackoverflow.com/a/19415703/842935
// Call backend
DataFromBackend = await Task.FromResult( Data + " from backend");
await InvokeAsync( StateHasChanged );
}
void IDisposable.Dispose()
=>
aTimer?.Dispose();
}用例:
此代码的一个用例是避免后端请求,因为在用户停止键入之前不会发送请求。
跑步:

发布于 2021-02-07 17:46:04
这个答案是前几个答案之间的中间点,即DIY和使用全面的反应性用户界面框架之间。
它利用了强大的Reactive.Extensions库(a.k.a )。在我看来,这是在正常情况下解决这些问题的唯一合理方法。
解决方案
安装NuGet包System.Reactive之后,可以在组件中导入所需的命名空间:
@using System.Reactive.Subjects
@using System.Reactive.Linq在组件上创建一个Subject字段,充当输入事件和Observable管道之间的粘合剂:
@code {
private Subject<ChangeEventArgs> searchTerm = new();
// ...
}将Subject与input连接起来
<input type="text" class="form-control" @oninput=@searchTerm.OnNext>最后,定义Observable管道:
@code {
// ...
private Thing[]? things;
protected override async Task OnInitializedAsync() {
searchTerm
.Throttle(TimeSpan.FromMilliseconds(200))
.Select(e => (string?)e.Value)
.Select(v => v?.Trim())
.DistinctUntilChanged()
.SelectMany(SearchThings)
.Subscribe(ts => {
things = ts;
StateHasChanged();
});
}
private Task<Thing[]> SearchThings(string? searchTerm = null)
=> HttpClient.GetFromJsonAsync<Thing[]>($"api/things?search={searchTerm}")
}上面的例子将..。
ChangeEventArgs中选择类型化值,things上,如果标记中有类似于以下内容的内容,则在键入以下内容时会看到它正在更新:
@foreach (var thing in things) {
<ThingDisplay Item=@thing @key=@thing.Id />
}附加说明
别忘了打扫卫生
您应该正确地释放事件订阅,如下所示:
@implements IDisposable // top of your component
// markup
@code {
// ...
private IDisposable? subscription;
public void Dispose() => subscription?.Dispose();
protected override async Task OnInitializedAsync() {
subscription = searchTerm
.Throttle(TimeSpan.FromMilliseconds(200))
// ...
.Subscribe(/* ... */);
}
}Subscribe()实际上返回一个应该与组件一起存储和释放的IDisposable。但是不要在上面使用using,因为这样会过早地破坏订阅。
公开问题
有些事情我还没弄清楚:
StateHasChanged()Subscribe()并直接绑定到标记内的Observable,就像您使用管道在角度上所做的那样Subject?Rx支持从Observable Events创建C#,但是如何获得oninput事件的C#对象?https://stackoverflow.com/questions/57533970
复制相似问题