DBerg
DBerg

Reputation: 15

C# Blazor EventCallBack is not set

I'm new to Blazor and was trying somethings out but i ran into a problem while trying to trigger a callback. My parent is Home.razor and contains:

@page "/"
<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

Increment:
<!-- Use @bind for two-way binding -->
<input type="number" @bind="_incrementAmount" />

<p>Increment amount: @_incrementAmount</p>

<Counter IncrementAmount="_incrementAmount"
         OnOddCount="@(async (count) => await OddCountDetected(count))"
         OnEvenCount="@(async (count) => await EvenCountDetected(count))">
</Counter>

<div style="color: red; height: @Count; min-height:5px; background-color:burlywood; overflow:auto;">
    <p>
        Odd? @_odd.ToString()
    </p>
</div>

@code {
    private int _incrementAmount { get; set; } = 1;
    private int _count { get; set; }
    private bool _odd;

    public string Count
    {
        get { return _count + "px"; }
        set { _count = int.Parse(value); }
    }

    public async Task OddCountDetected(int count)
    {
        Console.WriteLine($"OddCountDetected called in Home.razor with count: {count}"); // Debug log
        _count = count;
        _odd = true;
        StateHasChanged(); // Refresh the UI
    }

    public async Task EvenCountDetected(int count)
    {
        Console.WriteLine($"EvenCountDetected called in Home.razor with count: {count}"); // Debug log
        _odd = false;
        StateHasChanged(); // Refresh the UI
    }
}

My child is called Counter.razor and contains the following code

@page "/counter"
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    [Parameter]
    public int IncrementAmount { get; set; } = 1;

    [Parameter]
    public EventCallback<int> OnOddCount { get; set; }

    [Parameter]
    public EventCallback<int> OnEvenCount { get; set; }

    private async Task IncrementCount()
    {
        currentCount += IncrementAmount;

        Console.WriteLine($"Incrementing: Current count = {currentCount}, IncrementAmount = {IncrementAmount}");

        // Check if OnOddCount or OnEvenCount should be invoked
        if (int.IsOddInteger(currentCount))
        {
            Console.WriteLine($"Odd count detected: {currentCount}"); // Log when odd is detected

            // Check if there is an assigned delegate
            if (OnOddCount.HasDelegate)
            {
                Console.WriteLine("Invoking OnOddCount callback"); // Log when callback is invoked
                await OnOddCount.InvokeAsync(currentCount);
            }
            else
            {
                Console.WriteLine("OnOddCount has no delegate");
            }
        }
        else
        {
            Console.WriteLine($"Even count detected: {currentCount}"); // Log when even is detected

            // Check if there is an assigned delegate
            if (OnEvenCount.HasDelegate)
            {
                Console.WriteLine("Invoking OnEvenCount callback"); // Log when callback is invoked
                await OnEvenCount.InvokeAsync(currentCount);
            }
            else
            {
                Console.WriteLine("OnEvenCount has no delegate");
            }
        }
    }
}

In this case every time i trigger the IncrementCount() method OnOddCount.HasDelegate and OnEvenCount.HasDelegate are both false.

I've tried to change the way i set the delegate by using the following code:

<Counter IncrementAmount="_incrementAmount"
         OnOddCount="@this.OddCountDetected"
         OnEvenCount="@this.EvenCountDetected">
</Counter>

&&

<Counter IncrementAmount="_incrementAmount"
         OnOddCount="@OddCountDetected"
         OnEvenCount="@EvenCountDetected">
</Counter>

and ive also tried what is stated in this question as the answer: Blazor EventCallback parameter not firing

But even when i tried that it still didnt get set.

Additionally what might be another symptom is the fact that @_incrementAmount does not trigger StateHasChanged() and as such does not show the new value on the page.

Upvotes: 1

Views: 203

Answers (1)

MrC aka Shaun Curtis
MrC aka Shaun Curtis

Reputation: 30177

Firstly, make sure your running in interactive mode. I've set my project to Server, but it can be either. Just note it's much easier and quicker to debug in Server Mode when your experimenting.

First My App showing global interactivity enabled.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
    <link rel="stylesheet" href="SO79018875.styles.css" />
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet @rendermode="InteractiveServer" />
</head>

<body>
    <Routes @rendermode="InteractiveServer" />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>

The Counter Page

@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    [Parameter] public int IncrementAmount { get; set; } = 1;

    [Parameter] public EventCallback<int> OnOddCount { get; set; }

    [Parameter] public EventCallback<int> OnEvenCount { get; set; }

    private async Task IncrementCount()
    {
        currentCount += IncrementAmount;

        Console.WriteLine($"Incrementing: Current count = {currentCount}, IncrementAmount = {IncrementAmount}");

        // Check if OnOddCount or OnEvenCount should be invoked
        if (int.IsOddInteger(currentCount))
        {
            Console.WriteLine($"Odd count detected: {currentCount}"); // Log when odd is detected

            // Check if there is an assigned delegate
            if (OnOddCount.HasDelegate)
                Console.WriteLine("Invoking OnOddCount callback"); // Log when callback is invoked
            else
                Console.WriteLine("OnOddCount has no delegate");
            
            // Just call it.  It handles a null delegate
            await OnOddCount.InvokeAsync(currentCount);
        }
        else
        {
            Console.WriteLine($"Even count detected: {currentCount}"); // Log when even is detected

            // Check if there is an assigned delegate
            if (OnEvenCount.HasDelegate)
                Console.WriteLine("Invoking OnEvenCount callback"); // Log when callback is invoked
            else
                Console.WriteLine("OnEvenCount has no delegate");

            await OnEvenCount.InvokeAsync(currentCount);
        }
    }
}

And the Home Page:

@page "/"
<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

Increment:
<!-- Use @bind for two-way binding -->
<input class="form-control mb-3" type="number" @bind="_incrementAmount" />

<p>Increment amount: @_incrementAmount</p>

<Counter IncrementAmount="_incrementAmount"
         OnOddCount="OddCountDetected"
         OnEvenCount="EvenCountDetected">
</Counter>

<div class="bg-dark text-white m-2 p-2" >
    <pre>
        Odd? @_odd.ToString()
    </pre>
</div>

@code {
    private int _incrementAmount { get; set; } = 1;
    private int _count { get; set; }
    private bool _odd;

    public Task OddCountDetected(int count)
    {
        Console.WriteLine($"OddCountDetected called in Home.razor with count: {count}");
        _count = count;
        _odd = true;
        return Task.CompletedTask;
    }

    public Task EvenCountDetected(int count)
    {
        Console.WriteLine($"EvenCountDetected called in Home.razor with count: {count}");
        _odd = false;
        return Task.CompletedTask;
    }
}

The key points to highlight are:

  1. No StateHasChanged calls, they are built in to ComponentBase.
  2. Removal of a lot of unnecessary async calling.

Upvotes: 1

Related Questions