liveBook · Manning

Data binding

As explained in Pro ASP.NET Core 7, Tenth Edition

A Blazor component binding that associates a component value parameter with a property on the edited model.

Data binding keeps a Blazor value and a C# property in step. For an HTML input, a property supplies the displayed value; a user change updates the property. Without a binding, that relationship takes both a value expression and a change-event handler. The @bind attribute expresses both directions in one place. section 33.4.2

Bind an input

In Bindings.razor, @bind="City" connects an input to a City property initialized to London. After editing the input, move focus away: its default change event then updates City and the displayed City value. Buttons that set City to Paris or Chicago demonstrate the reverse direction—the input displays the new property value. section 33.4.2

If waiting for the change event is too slow, use @bind-value="City" with @bind-value:event="oninput" to update as input occurs. DateTime bindings can also specify @bind:culture and @bind:format; a date input can bind directly to the same DateTime property. section 33.4.2

Listing 33.19 Specifying an event in the Bindings.razor file in the Blazor folder
<div class="form-group">
    <label>City:</label>
    <input class="form-control" @bind-value="City"
           @bind-value:event="oninput" />
</div>
<div class="p-2 mb-2">City Value: @City</div>
<button class="btn btn-primary" @onclick="@(() => City = "Paris")">
    Paris
</button>
<button class="btn btn-primary" @onclick="@(() => City = "Chicago")">
    Chicago
</button>

@code {
    public string? City { get; set; } = "London";
}

Shows the City binding configured to use oninput rather than the default change event. section 33.4.2

Binding also works across component boundaries. A child component must expose a value parameter and an EventCallback<T> parameter named by appending Changed to the value name. Apply [Parameter] to both. A parent can then use @bind-SelectedValue="SelectedCity" instead of wiring the value and callback separately. Selecting a city in the child changes the parent's highlighted table row; changing SelectedCity in the parent changes the child's selection. section 34.2.2

Listing 34.14 Using a custom binding in the PeopleList.razor file in the Blazor folder
<table class="table table-sm table-bordered table-striped">
    <thead>
        <tr>
            <th>ID</th><th>Name</th><th>Dept</th><th>Location</th>
        </tr>
    </thead>
    <tbody>
        @foreach (Person p in People ?? Enumerable.Empty<Person>()) {
            <tr class="@GetClass(p?.Location?.City)">
                <td>@p?.PersonId</td>
                <td>@p?.Surname, @p?.Firstname</td>
                <td>@p?.Department?.Name</td>
                <td>@p?.Location?.City, @p?.Location?.State</td>
            </tr>
        }
    </tbody>
</table>

<SelectFilter values="@Cities" title="@SelectTitle" 
    @bind-SelectedValue="SelectedCity" />

<button class="btn btn-primary mt-2" 
    @onclick="@(() => SelectedCity = "Oakland")">
        Change
</button>

@code {

    [Inject]
    public DataContext? Context { get; set; }
 
    public IEnumerable<Person>? People => Context?.People
            .Include(p => p.Department)
            .Include(p => p.Location).Take(ItemCount);
                        
    public IEnumerable<string>? Cities => 
        Context?.Locations.Select(l => l.City);
                
    public string SelectedCity { get; set; } = string.Empty;
        
    public string GetClass(string? city) =>
        SelectedCity == city ? "bg-info text-white" : "";
                
    [Parameter]
    public int ItemCount { get; set; } = 4;
 
    [Parameter]
    public string? SelectTitle { get; set; }
        
    //public void HandleCustom(string newValue) {
    //    SelectedCity = newValue;
    //}
}

Shows the parent binding a city-selection component to SelectedCity and changing that property with a button. section 34.2.2

For an edit form, put the model in EditForm's Model attribute and bind each input component's Value to the appropriate model property: for example, @bind-Value="PersonData.Firstname" on InputText or @bind-Value="PersonData.DepartmentId" on InputNumber. Match the component to the property's type; a mismatch causes an error when entered input is parsed. EditForm supplies the foundation for validation. section 36.2

Listing 36.7 Using form components in the Editor.razor file in the Blazor/Forms folder
@page "/forms/edit/{id:long}"
@layout EmptyLayout

<h4 class="bg-primary text-center text-white p-2">Edit</h4>

<FormSpy PersonData="PersonData">
    <EditForm Model="PersonData">
        <div class="form-group">
            <label>Person ID</label>
            <InputNumber class="form-control"
                @bind-Value="PersonData.PersonId" disabled />
        </div>
        <div class="form-group">
            <label>Firstname</label>
            <InputText class="form-control" 
                @bind-Value="PersonData.Firstname" />
        </div>
        <div class="form-group">
            <label>Surname</label>
            <InputText class="form-control" 
                @bind-Value="PersonData.Surname" />
        </div>
        <div class="form-group">
            <label>Dept ID</label>
            <InputNumber class="form-control"
                         @bind-Value="PersonData.DepartmentId" />
        </div>
        <div class="text-center">
            <NavLink class="btn btn-secondary" href="/forms">
                Back
            </NavLink>
        </div>
    </EditForm>
</FormSpy>

@code {

    [Inject]
    public NavigationManager? NavManager { get; set; }
        
    [Inject]
    DataContext? Context { get; set; }
 
    [Parameter]
    public long Id { get; set; }
 
    public Person PersonData { get; set; } = new();
        
    protected async override Task OnParametersSetAsync() {
        if (Context != null) {
            PersonData = await Context.People.FindAsync(Id) 
                ?? new Person();
        }
    }
}

Shows a routed editor binding InputText and InputNumber components to properties of an EditForm model. section 36.2

How Pro ASP.NET Core 7, Tenth Edition covers it

How deep it goes
Works through manual event wiring, binding attributes, custom component parameter conventions, and typed form controls; does not descend into binding internals.
Examples
Uses a city input and buttons, a city-selection component that highlights table rows, and an editor for person properties.
What it assumes
Assumes familiarity with C# properties and Razor component markup while demonstrating the value-and-event relationship from its separate parts.
What you can do after
Apply it via Blazor binding attributes to synchronize inputs and components, including typed controls inside EditForm.
How it connects
Connects Razor components, change events, EventCallback<T>, EditForm, model properties, and validation.

Also explained in

Compare how 5 books explain data binding →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Pro ASP.NET Core 7, Tenth Edition. The section links point to the parts of the book it draws on.