I'm just starting out on the web and this time I'm having trouble with event handling. I develop with blazor, but this seems like a universally applicable problem.
Where I'm stuck is this. I want to notify the page when I get a message. I had no problem with this when I had one browser screen, but when I test my web with two screens open, the events don't work properly. how do I fix this?
Below is my code.
ServiceInfoReceiveHandler.cs
public event EventHandler<(string contentType, string serverName, string message)> InstallServiceInfoReceived;
...
public void Receive(BasicDeliverEventArgs eventArgs)
{
if (contentType == "SVCMGMT/INSTALL/SVCINFO")
{
InstallServiceInfoReceived?.Invoke(this, (contentType, serverName, message));
...
}
}
I fire the event like this and the receive function is always called whenever a message comes in. It's not a matter of the message not arriving.
page.razor
@inject ServiceInfoReceiveHandler _serviceInfoReceiveHandler
protected override async Task OnInitializedAsync()
{
_serviceInfoReceiveHandler.InstallServiceInfoReceived += OnServiceInfoReceived;
}
private async void OnServiceInfoReceived(object sender, (string contentType, string serverName, string message) e)
{
...
}
The razor page I want the result of is like above, but OnInfoReceived is not called.
Here's a simple demonstration of the Blazor Notification pattern used to communicate between pages with events.
First a notification service.
namespace SO76170542.Data;
public class HelloService
{
public event EventHandler<HelloEventArgs>? HelloChanged;
private string? _hello;
public string HelloMessage => _hello ?? "No Message Set";
public void NotifyHelloChanged(string? hello)
{
_hello = hello;
this.HelloChanged?.Invoke(this, new(hello));
}
}
public class HelloEventArgs : EventArgs
{
public string? Hello { get; set; }
public HelloEventArgs(string? hello)
=> Hello = hello;
}
Registered in Program.
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddSingleton<HelloService>();
var app = builder.Build();
And a page to generate and consume messages.
@page "/"
@inject HelloService helloService
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<div class="m-2">
<button class="btn btn-dark" @onclick=this.UpdateHello>Update Hello</button>
</div>
<div class="alert alert-primary">@helloService.HelloMessage</div>
@code {
// Register the event handler
protected override void OnInitialized()
=> this.helloService.HelloChanged += this.OnHelloChanged;
private Task UpdateHello()
{
helloService.NotifyHelloChanged($"Hello Blazor at {DateTime.Now.ToLongTimeString()}");
return Task.CompletedTask;
}
public void OnHelloChanged(object? sender, HelloEventArgs e)
=> InvokeAsync(this.StateHasChanged);
// We must de-register the even handler
public void Dispose()
=> this.helloService.HelloChanged -= this.OnHelloChanged;
}
You can see the same pattern applied to FetchData
here: How can I trigger/refresh my main .RAZOR page from all of its sub-components within that main .RAZOR page when an API call is complete?