Event callbacks complete the Blazor component communication circle by allowing a child component to send information to its parent component when the user triggers an action.
Blazor uses a component-driven application model. We’re building a tree of components to form a Blazor application.
It’s common for parent components to communicate with their child components. Using parameters, we can provide data from the parent to the child.
In this article, we will use event callbacks to send information from the child to its parent component.
Today, we will build a Blazor quiz application. You can access the code on GitHub.
Let’s start with the Question
component. It contains a Title
property and an AnswerA
and AnswerB
property. All properties
are of type string
.
<b>@Title</b>
<p>
Answer A: <button type="button" class="btn btn-primary">@AnswerA</button>
</p>
<p>
Answer B: <button type="button" class="btn btn-secondary">@AnswerB</button>
</p>
@code {
[Parameter]
public string Title { get; set; }
[Parameter]
public string AnswerA { get; set; }
[Parameter]
public string AnswerB { get; set; }
}
The idea is that each Question
component renders a question followed by two answer options. The user can provide an answer using the button representing each option.
All of the information is provided using component parameters. The Parameter
attribute applied to each property tells Blazor to require the attribute when using the Question
component.
Learn more about how Blazor components work and how parameters provide information from the parent component to its children in the Blazor Basics: Creating a Blazor Component article of this series.
In our example, the parent component is the Index
page of the application.
@page "/"
<PageTitle>Blazor Quiz</PageTitle>
<h1>Blazor Quiz</h1>
<p style="margin-bottom: 24px">Welcome to the Blazor Quiz!</p>
<h2>Questions</h2>
<Question Title="Does Blazor support event callbacks?" AnswerA="Yes" AnswerB="No" />
Besides the heading and other information rendered on the screen, the Index
page uses the Question
component, providing three strings to its Title
,
AnswerA
and AnswerB
attributes.
So far, we have provided data from the parent to the child component, but we do not communicate back.
Let’s change it by adding an event callback that fires when the user presses one of the answer buttons within the Question
component.
[Parameter]
public EventCallback OnAnswerASelected { get; set; }
[Parameter]
public EventCallback OnAnswerBSelected { get; set; }
First, we add two properties of type EventCallback
to the Question
component and name them OnAnswerASelected
and OnAnswerBSelected
.
We also add the Parameter
attribute because we want to provide the handler from the parent component.
As the names suggest, those callbacks will be fired when a user selects answer A or B. We fire the events by adding a reference to each of the answer buttons using their onclick
attribute.
The whole Question
component now looks like this:
<b>@Title</b>
<p>
Answer A: <button type="button" class="btn btn-primary" onclick="@OnAnswerASelected">@AnswerA</button>
</p>
<p>
Answer B: <button type="button" class="btn btn-secondary" onclick="@OnAnswerBSelected">@AnswerB</button>
</p>
@code {
[Parameter]
public string Title { get; set; }
[Parameter]
public string AnswerA { get; set; }
[Parameter]
public string AnswerB { get; set; }
[Parameter]
public EventCallback OnAnswerASelected { get; set; }
[Parameter]
public EventCallback OnAnswerBSelected { get; set; }
}
Next, we need to provide a handler for each event callback when using the Question
component on the Index
page.
@page "/"
<PageTitle>Blazor Quiz</PageTitle>
<h1>Blazor Quiz</h1>
<p style="margin-bottom: 24px">Welcome to the Blazor Quiz!</p>
<h2>Questions</h2>
<Question
Title="Does Blazor support event callbacks?"
AnswerA="Yes"
AnswerB="No"
OnAnswerASelected="@AnswerASelected"
OnAnswerBSelected="@AnswerBSelected" />
<p>The user pressed: @State</p>
@code {
public string State { get; set; } = "Nothing";
public void AnswerASelected()
{
State = "A";
}
public void AnswerBSelected()
{
State = "B";
}
}
Note the OnAnswerASelected
and OnAnswerBSelected
properties added to the Question
component that both reference a method from the code section.
We use a simple logic that changes the text on the screen depending on what button has been pressed. In a real quiz application, you might check whether the user clicked the correct answer and add or remove points.
Notice that we do not need to manually call the StateHasChanged
method because the EventCallback
type handles it internally and conveniently forces a re-render of the involved components.
Instead of using the OnAnswerASelected
event callback directly as the argument of the onclick
attribute of the button
, we can fire events from inside
C# methods.
The code would look like this:
public void OnButtonAClicked()
{
OnAnswerASelected.InvokeAsync();
}
The EventCallback
type provides an InvokeAsync
method that we can use to fire the event from within any C# method.
The wiring of the OnButtonAClicked
method to the component template looks like this:
@onclick="OnButtonAClicked"
As you can see, we can either use the EventCallback
property as the onclick
handler of a button
, or we can fire an event callback from inside any C#
component code.
So far, we defined an EventCallback
inside the child component and added a handler method in the parent component by providing it via component parameters.
But what if we want to pass information from the child component to the parent component when the event fires?
Blazor offers a generically typed implementation of the EventCallback
type. We can use it to provide context when the event fires.
Let’s define the following enum
type in the root of the project, so that it is available within both, the Index
page and the Question
component:
namespace BlazorQuiz;
public enum QuizAnswer
{
AnswerA,
AnswerB
}
Next, we want to use this type to pass information from the child component to its parent. We change the implementation of the Question
component like this:
<b>@Title</b>
<p>
Answer A: <button type="button" class="btn btn-primary" @onclick="() => AnswerSelected(QuizAnswer.AnswerA)">@AnswerA</button>
</p>
<p>
Answer B: <button type="button" class="btn btn-secondary" @onclick="() => AnswerSelected(QuizAnswer.AnswerB)">@AnswerB</button>
</p>
@code {
[Parameter]
public string Title { get; set; }
[Parameter]
public string AnswerA { get; set; }
[Parameter]
public string AnswerB { get; set; }
[Parameter]
public EventCallback<QuizAnswer> OnAnswerSelected { get; set; }
public void AnswerSelected(QuizAnswer answer)
{
OnAnswerSelected.InvokeAsync(answer);
}
}
We removed the specific event callbacks named OnAnswerASelected
and OnAnswerBSelected
and replaced them with a single OnAnswerSelected
event callback.
Notice the QuizAnswer
type argument.
Next, we added an AnswerSelected
method that accepts a single parameter of type QuizAnswer
and fires the OnAnswerSelected
event using its
InvokeAsync
method and passing the value received by its method parameter.
We also changed the wiring of the button tags in the component template. We call the AnswerSelected
method from within the onclick
attribute and provide the correct value of the
QuizAnswer
enum, depending on the button.
In the Index
page component, we also need to make a few changes.
@page "/"
<PageTitle>Blazor Quiz</PageTitle>
<h1>Blazor Quiz</h1>
<p style="margin-bottom: 24px">Welcome to the Blazor Quiz!</p>
<h2>Questions</h2>
<Question
Title="Does Blazor support event callbacks?"
AnswerA="Yes"
AnswerB="No"
OnAnswerSelected="@AnswerSelected" />
<p>The user pressed: @State</p>
@code {
public string State { get; set; } = "Nothing";
public void AnswerSelected(QuizAnswer answer)
{
if( answer == QuizAnswer.AnswerA)
{
State = "A";
}
else if( answer == QuizAnswer.AnswerB)
{
State = "B";
}
}
}
First, we provide a single event callback to the OnAnswerSelected
property of the Question
component. The implementation accepts a value of type QuizAnswer
as its first method parameter. We set the State
property depending on its value.
The implementation using the generic EventCallback
type is a lot more concise and provides better readability.
Instead of having multiple callbacks with verbose names, such as OnAnswerASelected
and OnAnswerBSelected
, we use a single OnAnswerSelected
event
callback.
When we use a child component in a parent component, we reference the child component using a custom HTML tag in the component’s template.
If the child component requires any parameter, we use HTML attributes to provide the information for each parameter.
When we want to send information from a child component to a parent based on a user action, we use event callbacks.
The Blazor EventCallback
type may sound a lot like classic .NET events. However, there are a few noteworthy differences.
First, .NET events can have multiple event handlers. Consider the following code:
Window.OnCloseEvent += HandleWindowClose;
We add the HandleWindowClose
method to a collection of handler methods. When using Blazor EventCallback
, we can only provide a single handler method. On the upside,
we do not need to unsubscribe from events like we would need to do using classic .NET events.
Second, .NET events are classes, while the Blazor EventCallback<T>
type is a struct. The advantage of using structs here is that we cannot assign null to
a property of a struct type. Therefore, we do not need to check for null values when firing a Blazor EventCallback
. Consider the following code:
OnAnswerSelected.InvokeAsync(answer);
We can call the InvokeAsync
method without checking for null because the compiler makes sure that the OnAnswerSelected
property always contains a value.
When using classic .NET events, the code would look like this:
OnCloseEvent?.Invoke(this, value);
There are a few more minor differences between classic .NET events and Blazor EventCallback
types. However, those two points are the most important differences to remember.
The EventCallback
type provides a simple API for communication between child and parent components in Blazor applications.
The generic EventCallback<T>
type allows us to provide context information when firing the event. It helps us write concise, readable, and maintainable code.
Event callbacks complete the communication circle between Blazor components. We use parameters to provide data from a parent to its child component. And we use event callbacks to provide information from the child component to its parent.
Try Telerik UI for Blazor
Want to dive into Blazor development with all the components you could want already built natively for you? Progress Telerik UI for Blazor helps you create professional-grade web projects in half the time with a high-performing Grid and 100+ easy-to-customize Blazor components to cover any requirement. Try it for free with our 30-day trial and enjoy our industry-leading support.
Claudio Bernasconi is a passionate software engineer and content creator writing articles and running a .NET developer YouTube channel. He has more than 10 years of experience as a .NET developer and loves sharing his knowledge about Blazor and other .NET topics with the community.