🎯 Blazor Component Interaction
The Walkie-Talkie Story
Imagine you have a walkie-talkie. You press a button, you talk, and your friend hears you. They press their button, they talk, and you hear them back.
That’s exactly how Blazor components talk to each other!
Components are like people with walkie-talkies. They can:
- 📢 Shout when something happens (Event Handling)
- 📞 Call their parent back (Event Callbacks)
- 🔄 Share and sync information (Data Binding)
- 📻 Broadcast to everyone at once (Cascading Values)
🎮 Event Handling in Blazor
What Is It?
Think of a button in a game. You press it → something happens!
In Blazor, event handling means:
“When the user does something, run my code!”
The Magic Formula
<button @onclick="DoSomething">
Click Me!
</button>
@code {
void DoSomething()
{
Console.WriteLine("Button clicked!");
}
}
Breaking It Down
| Part | What It Means |
|---|---|
@onclick |
“When clicked…” |
"DoSomething" |
“…run this method” |
Common Events (Like Different Walkie-Talkie Buttons)
graph TD A["User Actions"] --> B["@onclick<br/>Click/Tap"] A --> C["@oninput<br/>Type something"] A --> D["@onchange<br/>Pick a choice"] A --> E["@onsubmit<br/>Send a form"]
Real Example: A Counter
<h3>Count: @count</h3>
<button @onclick="AddOne">
+1
</button>
@code {
int count = 0;
void AddOne()
{
count++;
}
}
What happens:
- User sees “Count: 0”
- User clicks button
AddOne()runs → count becomes 1- Screen updates to “Count: 1”
Passing Event Data
Sometimes you need extra info about what happened:
<input @oninput="HandleTyping" />
@code {
void HandleTyping(ChangeEventArgs e)
{
string typed = e.Value?.ToString();
Console.WriteLine(quot;User typed: {typed}");
}
}
Think of it like: The walkie-talkie not just saying “button pressed” but also “button pressed AND here’s what they said…”
📞 Blazor Event Callbacks
The Problem
You have a child component (like a button component). When clicked, you want to tell the parent component what happened.
It’s like a kid with a walkie-talkie calling their parent!
The Solution: EventCallback
graph TD A["Parent Component"] -->|Gives walkie-talkie| B["Child Component"] B -->|Calls back| A
Step 1: Child Component (ChildButton.razor)
<button @onclick="NotifyParent">
@ButtonText
</button>
@code {
[Parameter]
public string ButtonText { get; set; }
[Parameter]
public EventCallback OnClicked { get; set; }
async Task NotifyParent()
{
await OnClicked.InvokeAsync();
}
}
Step 2: Parent Component
<ChildButton
ButtonText="Click me!"
OnClicked="HandleChildClick" />
<p>Child clicked @clickCount times</p>
@code {
int clickCount = 0;
void HandleChildClick()
{
clickCount++;
}
}
Passing Data Back to Parent
What if the child wants to send information back?
Child (RatingPicker.razor):
<button @onclick="() => SendRating(1)">⭐</button>
<button @onclick="() => SendRating(2)">⭐⭐</button>
<button @onclick="() => SendRating(3)">⭐⭐⭐</button>
@code {
[Parameter]
public EventCallback<int> OnRatingPicked { get; set; }
async Task SendRating(int stars)
{
await OnRatingPicked.InvokeAsync(stars);
}
}
Parent:
<RatingPicker OnRatingPicked="SaveRating" />
<p>You picked: @rating stars</p>
@code {
int rating = 0;
void SaveRating(int stars)
{
rating = stars;
}
}
Key Points
| Concept | Think of it as… |
|---|---|
EventCallback |
A phone line to parent |
EventCallback<T> |
A phone line that sends data too |
InvokeAsync() |
Making the call |
🔄 Data Binding in Blazor
What Is It?
Imagine a magic notebook. When you write something, it appears on the screen. When the screen shows something, it’s in your notebook.
They’re always in sync!
One-Way Binding (Screen Shows Notebook)
<p>Hello, @name!</p>
@code {
string name = "Alex";
}
The screen shows what’s in name. Change name → screen updates.
Two-Way Binding (Both Sync Each Other)
<input @bind="name" />
<p>Hello, @name!</p>
@code {
string name = "Alex";
}
graph LR A["Input Box"] <--> B["Name variable"] B --> C["Display"]
What happens:
- Screen shows “Alex” in the input
- User types “Sam”
- Variable
namebecomes “Sam” - The
<p>updates to “Hello, Sam!”
Binding with Specific Events
By default, @bind updates when you leave the field. Want instant updates?
<input @bind="name" @bind:event="oninput" />
Now it updates as you type!
Binding Different Types
<!-- Text -->
<input @bind="username" />
<!-- Number -->
<input type="number" @bind="age" />
<!-- Checkbox -->
<input type="checkbox" @bind="isHappy" />
<!-- Dropdown -->
<select @bind="color">
<option>Red</option>
<option>Blue</option>
<option>Green</option>
</select>
Component Two-Way Binding
You can make your own components support @bind!
Child (NameInput.razor):
<input value="@Value"
@oninput="UpdateValue" />
@code {
[Parameter]
public string Value { get; set; }
[Parameter]
public EventCallback<string> ValueChanged { get; set; }
async Task UpdateValue(ChangeEventArgs e)
{
await ValueChanged.InvokeAsync(
e.Value?.ToString()
);
}
}
Parent:
<NameInput @bind-Value="personName" />
<p>Name is: @personName</p>
@code {
string personName = "Jo";
}
The Magic Recipe:
- Parameter named
Value - EventCallback named
ValueChanged - Parent uses
@bind-Value
📻 Cascading Values
The Problem
Imagine you have a family tree of components:
GrandParent
└── Parent
└── Child
└── GrandChild
If GrandParent wants to share data with GrandChild, normally you’d have to pass it down through every level. That’s tedious!
The Solution: Cascading Values
It’s like a radio station! GrandParent broadcasts, and anyone in the family can tune in.
graph TD A["📻 GrandParent<br/>#40;Broadcaster#41;"] -->|Broadcasts theme| B["Parent"] A -->|Broadcasts theme| C["Child"] A -->|Broadcasts theme| D["GrandChild"]
Step 1: Broadcasting (Provider)
<!-- In GrandParent.razor -->
<CascadingValue Value="@theme">
<Parent />
</CascadingValue>
@code {
string theme = "dark";
}
Step 2: Receiving (Consumer)
Any descendant can receive:
<!-- In GrandChild.razor -->
<div class="@Theme">
I'm using the @Theme theme!
</div>
@code {
[CascadingParameter]
public string Theme { get; set; }
}
Named Cascading Values
What if you broadcast multiple things?
<CascadingValue Value="@theme" Name="AppTheme">
<CascadingValue Value="@user" Name="CurrentUser">
<MainContent />
</CascadingValue>
</CascadingValue>
@code {
string theme = "dark";
User user = new User { Name = "Alex" };
}
Receiving specific values:
@code {
[CascadingParameter(Name = "AppTheme")]
public string Theme { get; set; }
[CascadingParameter(Name = "CurrentUser")]
public User User { get; set; }
}
Real-World Example: Theme Switcher
App.razor (Broadcaster):
<CascadingValue Value="@isDarkMode">
<Router ... />
</CascadingValue>
@code {
bool isDarkMode = true;
}
Any Page (Receiver):
<div class="@(IsDark ? "bg-black" : "bg-white")">
Content here
</div>
@code {
[CascadingParameter]
public bool IsDark { get; set; }
}
Cascading Value vs Parameter
| Feature | [Parameter] |
[CascadingParameter] |
|---|---|---|
| Passed by | Parent directly | Any ancestor |
| Explicit? | Yes, in markup | No, automatic |
| Best for | Direct parent-child | Deep nesting |
🎯 Quick Summary
graph TD A["Component Interaction"] --> B["Event Handling"] A --> C["Event Callbacks"] A --> D["Data Binding"] A --> E["Cascading Values"] B --> B1["@onclick, @oninput<br/>React to user actions"] C --> C1["EventCallback<br/>Child tells Parent"] D --> D1["@bind<br/>Two-way sync"] E --> E1["CascadingValue<br/>Broadcast to all"]
The Walkie-Talkie Cheat Sheet
| Need to… | Use This |
|---|---|
| React when user clicks/types | @onclick, @oninput |
| Tell parent something happened | EventCallback |
| Keep input and variable in sync | @bind |
| Share data with all descendants | CascadingValue |
🚀 You Did It!
You now understand how Blazor components talk to each other:
- ✅ Event Handling - React to what users do
- ✅ Event Callbacks - Child calls parent
- ✅ Data Binding - Keep things in sync
- ✅ Cascading Values - Broadcast to everyone
Remember: Components are like people with walkie-talkies. Now you know all the ways they can communicate!
