Reputation: 15
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
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:
StateHasChanged
calls, they are built in to ComponentBase
.async
calling.Upvotes: 1