Event Handling and Data Binding in Blazor

Blazor Basics Deep Dive: Your Step-by-Step Guide to Learning.razor

Blazor Basics Deep Dive: Your Step-by-Step Guide to Learning.razor

Welcome to this hands-on tutorial where we'll explore two fundamental concepts in Blazor: Event Handling and Data Binding. If you're using Blazor Server, you're in the right place! We'll build a single component, Learning.razor, that acts as your personal playground to see these ideas in action.

By the end, you'll not only understand what these concepts are but also how to implement them in your own Blazor Server applications.

What is Blazor Server, Briefly?

Imagine your web application's brain (your C# code) lives on a powerful computer called a "server." When someone uses your website in their browser, the browser sends small messages to this server. Your C# code runs on the server, makes decisions, and then only the tiny changes needed for your screen are sent back to the browser. This makes your web pages feel fast and interactive, even though the main logic is happening far away!

Part 1: Setting Up Your Blazor Server Project and Learning.razor

First, let's get your Blazor Server project ready and create our special Learning.razor component.

Step 1: Create a Blazor Server App (If You Haven't)

If you already have a Blazor Server App, you can skip this. Otherwise:

  1. Open Visual Studio (or your preferred .NET development tool).
  2. Choose to "Create a new project."
  3. Search for "Blazor Server App" and select it.
  4. Follow the prompts: give your project a name (e.g., MyBlazorLearningApp), choose a location, and click "Create."

Step 2: Create the Learning.razor and Learning.razor.cs Files

We'll use a common Blazor practice: keeping the HTML (what you see) in one file (.razor) and the C# code (what happens behind the scenes) in another (.razor.cs). These are called "partial classes."

  1. Find the Pages Folder: In your Visual Studio Solution Explorer, expand your project, then look for the Components folder, and inside that, the Pages folder. This is where Blazor pages (routable components) live.
  2. Create Learning.razor:
    • Right-click on the Pages folder.
    • Select Add > Razor Component....
    • Name the file Learning.razor and click Add.
  3. Create Learning.razor.cs (Code-Behind File):
    • Right-click on the Learning.razor file you just created (in the Solution Explorer).
    • Select Add > Class....
    • Name the file Learning.razor.cs (it's important that it's the exact same name as the .razor file, plus .cs). Click Add.

Important: Once created, you'll see Learning.razor.cs nested under Learning.razor in the Solution Explorer, indicating they're linked.

Step 3: Add the Initial Code to Your Files

Open both Learning.razor and Learning.razor.cs and paste the following code into them.

1. Learning.razor (The HTML and UI Layout)

This file defines what your page looks like. We're adding some simple styling using Tailwind CSS (a popular way to style web pages) directly in the component for this tutorial.

<!-- Components/Pages/Learning.razor -->
<!-- This file handles the visual layout and connects to the C# logic in Learning.razor.cs -->

@page "/learning"

<div class="min-h-screen bg-gray-100 p-8 flex flex-col items-center font-sans">
    <!-- !!! ALL OUR DEMO CODE WILL GO HERE !!! -->
</div>

2. Learning.razor.cs (The C# Logic)

This file will hold all the C# code that makes our page interactive. The partial keyword is important because it tells C# that this class is a "part" of the Learning.razor component.

// Components/Pages/Learning.razor.cs
// This file contains all the C# logic (properties and methods) for the Learning.razor component.
// The 'partial' keyword connects it to the .razor file.
using Microsoft.AspNetCore.Components; // Needed for Blazor-specific types like MouseEventArgs

namespace MyBlazorLearningApp.Components.Pages // !!! IMPORTANT: Make sure this matches your project's namespace !!!
{
    // The 'partial' keyword is crucial; it tells C# this class is part of the Learning.razor component.
    public partial class Learning
    {
        // Our C# variables (properties) and actions (methods) will be defined here.
        // They will be filled in as we go through each demo.
    }
}

Namespace Check: Double-check the namespace line in Learning.razor.cs. It should match the default namespace of your Blazor Server project (usually YourProjectName.Components.Pages). For example, if your project is MyWebApp, it might be MyWebApp.Components.Pages.

Part 2: Understanding Event Handling

What is it? Event handling is how your Blazor application responds to things a user does. This includes clicks, typing, mouse movements, and more. When an "event" happens in the browser, Blazor Server sends a tiny message to your C# code on the server, which then runs a specific action (a "method" or "event handler") you've defined.

Demo 1: Displaying Mouse Coordinates

Let's make an image that shows the X and Y position of your mouse pointer as you move over it.

How it Works (Blazor Server Style):

  • You move your mouse over the image in your browser.
  • The browser's Blazor runtime detects the mousemove event.
  • A tiny message goes over the internet (via SignalR) to your Blazor Server application.
  • Your C# Mouse_Move method runs on the server.
  • This method updates a C# variable (Coordinates).
  • Blazor Server sees the variable changed, figures out what part of the screen needs updating, and sends only that small change back to your browser.
  • The browser updates the text on your screen. All very fast!

Instructions:

  • Add to Learning.razor: Paste this HTML code inside the div that says <!-- !!! ALL OUR DEMO CODE WILL GO HERE !!! -->.
<!-- Demo Section 1: Mouse Coordinates Display -->
<div class="bg-white p-6 rounded-xl shadow-lg mb-8 w-full max-w-md">
    <h2 class="text-2xl font-semibold mb-4 text-gray-700">1. Display Mouse Coordinates (Event Handling)</h2>
    <p class="text-gray-600 mb-4">
        Move your mouse over the image below. The coordinates are updated by a C# method on the server.
    </p>
    <!-- The @onmousemove event calls the Mouse_Move method in our C# code -->
    <img class="card-img-top w-full h-48 object-cover rounded-md mb-4 shadow-md"
         src="https://placehold.co/400x200/60A5FA/FFFFFF?text=Hover+Over+Me"
         alt="Sample Image"
         @onmousemove="@Mouse_Move" />
    <p class="text-xl font-medium text-blue-700">Coordinates: <span class="font-bold">@Coordinates</span></p>

    <h3 class="text-xl font-semibold mt-6 mb-3 text-gray-700">Using an Inline Lambda Expression:</h3>
    <p class="text-gray-600 mb-4">
        For simple event logic, you can define the action directly in the HTML using a lambda expression.
    </p>
    <!-- This uses a lambda expression directly in the markup for the event handler -->
    <img class="card-img-top w-full h-48 object-cover rounded-md mb-4 shadow-md"
         src="https://placehold.co/400x200/6B7280/FFFFFF?text=Try+This+One+Too"
         alt="Sample Image Lambda"
         @onmousemove="@(e => CoordinatesLambda = $"X = {e.ClientX}, Y = {e.ClientY}")" />
    <p class="text-xl font-medium text-gray-800">Coordinates (Inline): <span class="font-bold">@CoordinatesLambda</span></p>
</div>
  • Add to Learning.razor.cs: Paste this C# code inside the public partial class Learning { ... } block.
// ... inside public partial class Learning { ... }

// --- Demo 1: Mouse Coordinates Display ---
// Property to store and display the mouse X and Y coordinates.
protected string Coordinates { get; set; } = "N/A";

// Property for the lambda expression example's coordinates.
protected string CoordinatesLambda { get; set; } = "N/A";

/// <summary>
/// Event handler for the 'onmousemove' event on an image.
/// Updates the 'Coordinates' property with the current mouse position.
/// </summary>
/// <param name="e">Provides data about the mouse event, like ClientX and ClientY.</param>
protected void Mouse_Move(MouseEventArgs e)
{
    Coordinates = $"X = {e.ClientX}, Y = {e.ClientY}";
    // In Blazor Server, changes to component properties like 'Coordinates' automatically
    // signal Blazor to re-render the affected parts of the UI.
}
Key Takeaways (Demo 1):
  • @onmousemove: This is a Blazor event attribute. It connects an HTML event (mouse moving) to a C# method.
  • Mouse_Move(MouseEventArgs e): This is our event handler method. It's a regular C# method that Blazor calls when the event happens. MouseEventArgs gives us useful info about the mouse.
  • @Coordinates: This is basic data binding (we'll cover this fully next!). It simply displays the value of our Coordinates C# variable. When the variable changes, the screen updates.
  • Lambda Expression: The @(e => ...) is a short, in-line way to write a small C# action directly in your HTML without needing a separate method. Useful for quick updates!

Demo 2: Show and Hide a Card Footer

Now, let's create a button that can hide or show a section of the page, and the button's text will change to reflect its action.

How it Works (Blazor Server Style):

  • You click the button in your browser.
  • A message travels to the Blazor Server.
  • Your C# Button_Click method runs on the server.
  • This method checks the current state and changes two C# variables: ButtonText and CssClass.
  • Blazor Server detects these changes and sends updates back to your browser to change the button's text and add/remove a special "hide" class on the footer.

Instructions:

  • Add to Learning.razor: Paste this HTML code right after the </div> closing tag of the previous demo's section.
<!-- Demo Section 2: Show/Hide Footer -->
<div class="bg-white p-6 rounded-xl shadow-lg mb-8 w-full max-w-md">
    <h2 class="text-2xl font-semibold mb-4 text-gray-700">2. Show/Hide Card Footer (Event Handling with CSS)</h2>
    <p class="text-gray-600 mb-4">
        Click the button to toggle the visibility of the grey card footer and change the button's text.
    </p>
    <div class="card bg-gray-50 border border-gray-200 rounded-md overflow-hidden">
        <div class="card-body p-4">
            <h5 class="card-title text-xl font-semibold mb-2 text-gray-800">Employee Card Example</h5>
            <p class="card-text text-gray-700 mb-4">This is some dummy content within the card body.</p>
            <!-- The @onclick event calls the Button_Click method -->
            <button class="btn bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-lg shadow-md transition duration-300 ease-in-out"
                    @onclick="@Button_Click">
                @ButtonText
            </button>
        </div>
        <!-- The @CssClass attribute dynamically applies a CSS class based on C# logic -->
        <div class="card-footer text-center p-4 bg-gray-100 border-t border-gray-200" @CssClass>
            <a href="#" class="btn bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded-lg shadow-sm mr-2 inline-block transition duration-300 ease-in-out">Back</a>
            <a href="#" class="btn bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-2 px-4 rounded-lg shadow-sm mr-2 inline-block transition duration-300 ease-in-out">Edit</a>
            <a href="#" class="btn bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded-lg shadow-sm inline-block transition duration-300 ease-in-out">Delete</a>
        </div>
    </div>
</div>
  • Add to Learning.razor.cs: Paste this C# code inside the public partial class Learning { ... } block, after the code for Demo 1.
// ... (code for Demo 1)

// --- Demo 2: Show/Hide Employee Card Footer ---
// Property for the text displayed on the button.
protected string ButtonText { get; set; } = "Hide Footer";

// Property to control the CSS class of the card footer, hence its visibility.
// Null means no extra class, so it's visible by default.
protected string CssClass { get; set; } = null;

/// <summary>
/// Event handler for the 'onclick' event of the button.
/// Toggles the visibility of the card footer and updates the button's text.
/// </summary>
protected void Button_Click()
{
    if (ButtonText == "Hide Footer")
    {
        ButtonText = "Show Footer";
        CssClass = "HideFooter"; // Apply the CSS class that hides the footer
    }
    else
    {
        CssClass = null; // Remove the CSS class to show the footer
        ButtonText = "Hide Footer";
    }
    // Blazor Server efficiently sends these UI updates to the client after the method runs.
}
Key Takeaways (Demo 2):
  • @onclick: This is another common event attribute for handling button clicks.
  • Dynamic Attributes: @ButtonText and @CssClass show how you can use C# variables to control HTML content (ButtonText) and even attributes (CssClass).
  • CSS for Hiding: We use a simple CSS class (.HideFooter { display: none; }) to hide or show the element. Your C# code just adds or removes this class.

Part 3: Understanding Data Binding

What is it? Data binding is the way Blazor connects your C# variables (in your code-behind) with the HTML elements on your page. It keeps them in sync, so if one changes, the other updates automatically. This saves you from writing lots of manual code to update your UI!

One-Way Data Binding (C# to UI)

In one-way binding, data flows from your C# code to your HTML. If a C# variable changes, the screen updates. But if a user types something on the screen, the C# variable does not change automatically.

Instructions:

  • Add to Learning.razor: Paste this HTML code right after the </div> closing tag of the previous demo's section.
<!-- Demo Section 3: One-Way Data Binding -->
<div class="bg-white p-6 rounded-xl shadow-lg mb-8 w-full max-w-md">
    <h2 class="text-2xl font-semibold mb-4 text-gray-700">3. One-Way Data Binding (C# to UI)</h2>
    <p class="text-gray-600 mb-4">
        Data flows from your C# properties to the UI. Changes made directly in the input box below will NOT update the C# property.
    </p>

    <div class="mb-4">
        <p class="text-lg text-gray-700"><b>Name (from simple property):</b> <span class="font-bold text-indigo-700">@NameOneWay</span></p>
    </div>

    <div class="mb-4">
        <p class="text-lg text-gray-700">
            <b>Name with Salutation (from Razor expression):</b>
            <span class="font-bold text-indigo-700">@(Gender == "Male" ? $"Mr. {NameOneWay}" : $"Ms. {NameOneWay}")</span>
        </p>
    </div>

    <div class="mb-4">
        <label for="oneWayInput" class="block text-gray-700 text-sm font-bold mb-2">Input Box (One-Way Value Bind):</label>
        <!-- The 'value' attribute shows the C# property, but does not send input back -->
        <input id="oneWayInput" type="text" value="@NameOneWay"
               class="shadow appearance-none border rounded-lg w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline focus:border-blue-500"
               placeholder="Type here, but it won't update the 'Name' above." />
        <p class="text-sm text-gray-500 mt-1">This input displays "@NameOneWay", but your typing stays local to the box.</p>
    </div>
</div>
  • Add to Learning.razor.cs: Paste this C# code inside the public partial class Learning { ... } block, after the code for Demo 2.
// ... (code for Demo 2)

// --- Demo 3: One-Way Data Binding ---
// Property used for one-way binding examples. Changes in UI won't affect this.
protected string NameOneWay { get; set; } = "Alice";

// Property used in a Razor expression to determine salutation.
protected string Gender { get; set; } = "Female";
Key Takeaways (Demo 3):
  • @PropertyName: This is the simplest way to display a C# property's value in HTML.
  • @() for Expressions: You can put any valid C# expression inside @(), and Blazor will calculate and display its result.
  • <input value="@PropertyName" />: This sets the initial value of an input from your C# property. But notice, if you type in this box, the NameOneWay variable in your C# code will not change. Data only flows one way here.

Two-Way Data Binding (Both Directions!)

This is incredibly powerful! Data flows both ways:

  • If your C# variable changes, the HTML updates (like one-way binding).
  • If the user interacts with the HTML (e.g., types in a box), the C# variable updates automatically.

Instructions:

  • Add to Learning.razor: Paste this HTML code right after the </div> closing tag of the previous demo's section.
<!-- Demo Section 4: Two-Way Data Binding -->
<div class="bg-white p-6 rounded-xl shadow-lg mb-8 w-full max-w-md">
    <h2 class="text-2xl font-semibold mb-4 text-gray-700">4. Two-Way Data Binding (Interactive UI)</h2>
    <p class="text-gray-600 mb-4">
        Data flows in both directions: C# to UI, and UI to C#. Your C# properties update as you interact with the UI.
    </p>

    <div class="mb-4">
        <label for="twoWayInput" class="block text-gray-700 text-sm font-bold mb-2">Your Name (updates on focus loss/Enter):</label>
        <!-- The @bind attribute simplifies two-way data binding. Default update is on 'onchange' event. -->
        <input id="twoWayInput" type="text" @bind="NameTwoWay"
               class="shadow appearance-none border rounded-lg w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline focus:border-blue-500"
               placeholder="Type here, then click outside or press Enter..." />
        <p class="text-sm text-gray-500 mt-1">
            Current C# Variable Value: <span class="font-bold text-purple-700">@NameTwoWay</span> (Updates when input loses focus)
        </p>
    </div>

    <div class="mb-4">
        <label for="twoWayInputRealtime" class="block text-gray-700 text-sm font-bold mb-2">Your Name (updates <em>as you type</em>):</label>
        <!-- @bind:event="oninput" changes the update trigger to the 'oninput' event for real-time changes. -->
        <input id="twoWayInputRealtime" type="text" @bind="NameTwoWayRealtime" @bind:event="oninput"
               class="shadow appearance-none border rounded-lg w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline focus:border-blue-500"
               placeholder="Type here for instant update..." />
        <p class="text-sm text-gray-500 mt-1">
            Current C# Variable Value: <span class="font-bold text-green-700">@NameTwoWayRealtime</span> (Watch it change instantly!)
        </p>
    </div>

    <div class="mb-4">
        <label for="colorInput" class="block text-gray-700 text-sm font-bold mb-2">Change Box Background Colour (by typing CSS):</label>
        <!-- @bind-ATTRIBUTE syntax binds to other HTML attributes, not just 'value' -->
        <input id="colorInput" type="text" @bind="Colour" @bind:event="oninput"
               class="shadow appearance-none border rounded-lg w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline focus:border-blue-500"
               placeholder="e.g., background-color:lightblue; color:darkblue; border-radius:10px;" />
        <div @bind-style="Colour" @bind-style:event="oninput"
             class="mt-2 p-4 border rounded-lg text-center text-gray-800 font-medium transition-all duration-300 ease-in-out">
            <h3>This box's background colour changes!</h3>
        </div>
        <p class="text-sm text-gray-500 mt-1">Type CSS properties into the input above to style this box.</p>
    </div>
</div>
  • Add to Learning.razor.cs: Paste this C# code inside the public partial class Learning { ... } block, after the code for Demo 3.
// ... (code for Demo 3)

// --- Demo 4: Two-Way Data Binding ---
// Property for two-way binding using default 'onchange' event.
protected string NameTwoWay { get; set; } = "Bob";

// Property for two-way binding using 'oninput' event for real-time updates.
protected string NameTwoWayRealtime { get; set; } = "Charlie";

// Property to store CSS style string, bound to a div's style attribute.
// Initialized with base styles that were previously in the static 'style' attribute.
protected string Colour { get; set; } = "min-height: 80px; display: flex; align-items: center; justify-content: center; background-color:white; color: black;";
Key Takeaways (Demo 4):
  • @bind="PropertyName": This is Blazor's simplified way to do two-way binding for input elements. It handles both displaying the value and updating the C# property when the input changes. By default, it uses the onchange event (updates when you finish typing or press Enter).
  • @bind:event="oninput": This is a powerful addition to @bind. It tells Blazor to update the C# property every time the oninput event fires (i.e., as you type each character), giving you real-time updates.
  • @bind-AttributeName="Property": You're not just limited to the value attribute of inputs! You can bind to other HTML attributes, like style, class, src, etc., using this pattern. This makes your UI highly dynamic.

Important Fix!: Remember, if you use @bind-style, you cannot also have a static style="..." attribute on the same HTML element. That's why we moved the base min-height, display, etc., into the initial value of the Colour C# property.

Demo 5: Real-World Example - Character Counter

This is a common feature on many websites! We'll build a text area that instantly tells you how many characters you've typed.

How it Works (Blazor Server Style):

This combines two-way binding and real-time updates perfectly. As you type, each character triggers an oninput event, which sends the new text to the server. Your Description C# property updates, and then Description.Length is recalculated. Blazor Server sends back just the updated character count to your browser.

Instructions:

  • Add to Learning.razor: Paste this HTML code right after the </div> closing tag of the previous demo's section.
<!-- Demo Section 5: Real-World Example - Character Counter -->
<div class="bg-white p-6 rounded-xl shadow-lg mb-8 w-full max-w-md">
    <h2 class="text-2xl font-semibold mb-4 text-gray-700">5. Real-World Example: Character Counter</h2>
    <p class="text-gray-600 mb-4">
        Type into the text area below and see the character count update immediately. This uses two-way binding with real-time updates.
    </p>

    <div class="mb-4">
        <label for="descriptionArea" class="block text-gray-700 text-sm font-bold mb-2">Write Your Description Here:</label>
        <!-- @bind="Description" with @bind:event="oninput" makes this a real-time character counter -->
        <textarea id="descriptionArea" class="shadow appearance-none border rounded-lg w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline focus:border-blue-500"
                  rows="5"
                  @bind="Description" @bind:event="oninput"
                  placeholder="Start typing your description..."></textarea>
    </div>
    <div class="mt-2 text-right">
        <strong class="text-lg text-orange-700">Character Count:</strong> <span class="text-xl font-bold text-orange-700">@Description.Length</span>
    </div>
</div>
  • Add to Learning.razor.cs: Paste this C# code inside the public partial class Learning { ... } block, after the code for Demo 4.
// ... (code for Demo 4)

// --- Demo 5: Real-World Example - Character Counter ---
/// <summary>
/// Property to hold the text content of the textarea for the character counter.
/// It's initialized to an empty string to prevent NullReferenceExceptions during rendering.
/// </summary>
public string Description { get; set; } = string.Empty;
Key Takeaways (Demo 5):
  • string.Empty Initialization: Always initialize string properties you're binding to, especially for input fields. If Description were null, Description.Length would cause an error.
  • Practical Use: This shows how simple Blazor syntax can build common and useful UI features efficiently.

Part 4: Running Your Blazor Server App and Learning.razor

Now that all the code is in place, let's see your interactive Learning.razor page!

  1. Build Your Project:
    • In Visual Studio, go to Build menu > Build Solution. (This ensures all your new code is compiled).
  2. Run Your Project:
    • Press F5 (or click the green "Play" button in Visual Studio's toolbar).
    • Your Blazor Server App will start and open in your default web browser.
  3. Navigate to Your Page:
    • The browser will likely open to the default home page (e.g., https://localhost:XXXX/).
    • To see your Learning.razor page, simply add /learning to the end of the URL in your browser's address bar. For example, if your app opens at https://localhost:7000/, change it to https://localhost:7000/learning.
  4. Interact!
    • Move your mouse over the images in Demo 1.
    • Click the button in Demo 2.
    • Type in the input boxes in Demo 3 and 4, paying attention to how NameTwoWay and NameTwoWayRealtime update differently.
    • Type CSS styles into the input box for the "Background Colour" in Demo 4.
    • Write a long description in the textarea in Demo 5 and watch the character count.

Conclusion

You've successfully created a powerful Learning.razor component that beautifully demonstrates Blazor Server's Event Handling and Data Binding capabilities!

  • You learned how to react to user actions (like mouse movements and clicks) using event handlers (@onmousemove, @onclick).
  • You saw how to display C# data on the UI (one-way binding) and how to keep C# data and UI inputs synchronized automatically (two-way binding using @bind and @bind:event).
  • Crucially, you understand that in Blazor Server, these interactions involve small, efficient communications between your browser and the C# code running on the server.

Keep experimenting with these concepts – they are the foundation for building dynamic and engaging web applications with Blazor!

Comments

Popular posts from this blog

Blazor: Building Web Apps with C# - Introduction

Blazor WebAssembly Hosted App Tutorial: Envelope Tracker System

Securing MVC-based Applications Using Blazor