0Pricing
C# Academy · 课时

数据绑定与事件处理

应用单向和双向数据绑定,处理 DOM 与组件事件,并使用 EventCallback。

数据绑定与事件处理 是 CoddyKit 上的免费 C# Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

Blazor 中的绑定

Blazor 支持三种绑定方向:单向(只读,@expr)、基于事件(@onclick 等)和双向(@bind)。它们共同构成响应式用户界面的基础。

单向数据绑定

只需在标记中使用 @ 输出 C# 表达式即可。每次组件重新渲染时,该值都会更新,但 DOM 无法将值传回 C#。

<!-- One-way: C# -> DOM -->
<p>Count: @_count</p>
<p>Full name: @($"{_firstName} {_lastName}")</p>
<p>Price: @Price.ToString("C")</p>

@code {
    private int _count = 0;
    private string _firstName = "Alice";
    private string _lastName = "Smith";
    [Parameter] public decimal Price { get; set; }
}

使用 @bind 进行双向绑定

@bind 会同时使用属性设置和更改事件,将输入元素连接到一个字段。它适用于文本、数字、日期、复选框和选择框。

<input @bind="_name" placeholder="Enter name" />
<input type="number" @bind="_quantity" />
<input type="date" @bind="_dueDate" />
<input type="checkbox" @bind="_isActive" />

<p>Name: @_name | Qty: @_quantity | Active: @_isActive</p>

@code {
    private string _name = "";
    private int _quantity = 1;
    private DateTime _dueDate = DateTime.Today;
    private bool _isActive = true;
}

使用自定义事件的 @bind

默认情况下,@bind 使用 onchange 事件。使用 @bind:event 可以更改事件——例如,oninput 会在每次按键时触发,适用于实时搜索。

@* Updates on every keystroke instead of on focus-loss *@
<input @bind="_search"
       @bind:event="oninput"
       placeholder="Live search..." />

<ul>
    @foreach (var item in Filtered)
    {
        <li>@item</li>
    }
</ul>

@code {
    private string _search = "";
    private string[] Items = { "Apple", "Banana", "Cherry", "Avocado" };
    private IEnumerable<string> Filtered =>
        Items.Where(i => i.Contains(_search, StringComparison.OrdinalIgnoreCase));
}

使用 @onclick 处理事件

使用 @onclick(以及其他 DOM 事件指令)将 C# 委托附加到 DOM 事件。同步方法和 async 任务都可以正常工作。

<button @onclick="Increment">+</button>
<button @onclick="DecrementAsync">-</button>
<button @onclick="() => _count = 0">Reset</button>
<p>Count: @_count</p>

@code {
    private int _count = 0;

    private void Increment() => _count++;

    private async Task DecrementAsync()
    {
        await Task.Delay(200); // simulate async work
        _count--;
    }
}

事件参数

DOM 事件会提供事件参数对象。请在处理程序中声明适当的参数类型,以访问坐标、键码、输入值等。

<input @onkeydown="OnKeyDown" @onfocus="OnFocus" />
<div @onmousemove="OnMouseMove">Move here</div>
<p>@_info</p>

@code {
    private string _info = "";

    private void OnKeyDown(KeyboardEventArgs e)
        => _info = $"Key: {e.Key} (Ctrl={e.CtrlKey})";

    private void OnFocus(FocusEventArgs e)
        => _info = "Input focused";

    private void OnMouseMove(MouseEventArgs e)
        => _info = $"Mouse: ({e.ClientX}, {e.ClientY})";
}

使用 EventCallback 进行父子通信

EventCallback 是 Blazor 中实现子组件与父组件通信的方式。与常规的 Action/Func 不同,它会自动在父组件上触发 StateHasChanged,并正确处理异常。

@* Child: ProductCard.razor *@
<button @onclick="() => OnBuy.InvokeAsync(Product)">Buy</button>

@code {
    [Parameter] public Product Product { get; set; } = default!;
    [Parameter] public EventCallback<Product> OnBuy { get; set; }
}

@* Parent: *@
<ProductCard Product="p" OnBuy="HandleBuy" />

@code {
    private async Task HandleBuy(Product p)
    {
        await CartService.AddAsync(p);
        // Parent re-renders automatically
    }
}

阻止默认行为和停止传播

使用 @onclick:preventDefault 取消浏览器的默认操作,使用 @onclick:stopPropagation 停止事件冒泡。

@* Prevent form submission *@
<form @onsubmit="HandleSubmit" @onsubmit:preventDefault>
    <input @bind="_value" />
    <button type="submit">Save</button>
</form>

@* Stop click from bubbling to parent div *@
<div @onclick="ParentClicked">
    <button @onclick="ChildClicked"
            @onclick:stopPropagation>
        Click me
    </button>
</div>

在自定义组件上使用 @bind-Value 进行双向绑定

在自定义组件上实现 Value/ValueChanged 模式,即可支持父组件中的 @bind-Value——这是 Blazor 标准的双向绑定契约。

@* RatingInput.razor *@
@for (int i = 1; i <= 5; i++)
{
    int star = i;
    <span class="@(star <= Value ? "filled" : "")"
          @onclick="() => ValueChanged.InvokeAsync(star)">★</span>
}

@code {
    [Parameter] public int Value { get; set; }
    [Parameter] public EventCallback<int> ValueChanged { get; set; }
}

@* Usage: *@
<RatingInput @bind-Value="_rating" />

对输入事件进行防抖

对于由用户输入触发的高成本操作(API 调用、复杂筛选),请使用 CancellationTokenSource 对事件进行防抖,在用户停止输入后再延迟执行。

@code {
    private string _query = "";
    private CancellationTokenSource? _cts;

    private async Task OnSearchInput(ChangeEventArgs e)
    {
        _query = e.Value?.ToString() ?? "";
        _cts?.Cancel();
        _cts = new CancellationTokenSource();

        try
        {
            await Task.Delay(300, _cts.Token); // wait 300ms
            Results = await SearchService.SearchAsync(_query);
        }
        catch (TaskCanceledException) { /* user still typing */ }
    }

    private List<string> Results = new();
}

快速检查

在 Blazor 中,对于子组件向父组件传递的事件,EventCallback 比 Action/Func 有什么优势?

回顾:数据绑定与事件处理

要点:

  • 单向绑定:使用 @expr 输出 C# 表达式
  • 双向绑定:在输入元素上使用 @bind;使用 @bind:event 更改触发事件
  • DOM 事件:@onclick、@oninput、@onkeydown 配合类型化事件参数
  • EventCallback<T>:带有自动 StateHasChanged 的子父通信
  • 实现 Value/ValueChanged,以支持自定义组件的双向绑定
  • 对高成本操作进行防抖,以减少不必要的 API 调用

常见问题解答

「数据绑定与事件处理」课时是免费的吗?

是的 — 「数据绑定与事件处理」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「数据绑定与事件处理」这节课中我会学到什么?

应用单向和双向数据绑定,处理 DOM 与组件事件,并使用 EventCallback。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「数据绑定与事件处理」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Blazor 组件模型
  2. 数据绑定与事件处理
  3. 组件通信与 DI
  4. Blazor 中的状态管理
← 返回 C# Academy