提问人:Alan 提问时间:10/26/2023 最后编辑:Alan 更新时间:10/26/2023 访问量:50
Blazor Server 中未触发事件
Event not firing in Blazor Server
问:
我在 AuthenticationService.cs 中创建了一个事件:
public event Action<string?>? LoginChanged;
在 AuthenticationService 的 Login 方法中,我调用了该事件:
LoginChanged?.Invoke(username); // This line does get hit when the user logs in, but LoginChanged is null
该事件在 BlazorServer 组件中订阅:
UserPartial.razor:
@inject IAuthenticationService AuthenticationService;
...
protected override void OnInitialized()
{
Logger.LogInformation("user.razor initilised 1"); // This does get hit
AuthenticationService.LoginChanged += (string? name) =>
{
Logger.LogInformation("event firing!!!"); // This doesn't get hit
username = name;
StateHasChanged();
};
Logger.LogInformation("user.razor initilised 2"); // This does get hit
base.OnInitialized();
}
AuthenticationService 的依赖项注入在程序 .cs 中设置为单一实例:
builder.Services.AddSingleton<IAuthenticationService, AuthenticationService>();
我的目标是,当 AuthenticationService 的 Login 方法调用 LoginChanged 事件时,将运行 UserPartial.razor 中的事件处理代码。
似乎正在发生的事情是,当 LoginChanged?.调用 Invoke(username),则 LoginEvent 为 null,因此它实际上不会调用。
我尝试了许多附加事件处理程序代码的替代方法,包括在 UserPartial.razor 中创建一个方法,如下所示:
public void LocalLoginChanged(string? name)
{
Logger.LogInformation("event firing!!!");
username = name;
StateHasChanged();
}
并像这样从 OnInitialized 附加它:
AuthenticationService.LoginChanged += new Action<string?>(LocalLoginChanged);
我尝试过其他方法,例如从 OnInitializedAsync 而不是 OnInitialized 调用它,但我尝试的所有内容都有相同的结果。
我错过了什么?为什么 LoginChanged 在调用它时为 null?显然我没有正确设置它,你能给我指出它应该如何设置的方向吗?
我正在使用 .Net Core 7、Blazor Server。
答:
如果将 注册为单一实例服务,则事件处理程序可能无法正确连接到组件的特定实例。AuthenticationService
在调用事件之前,请确保该事件不为 null。LoginChanged
public void OnLoginChanged(string? username)
{
LoginChanged?.Invoke(username);
}
订阅 中的事件。LoginChanged
OnInitializedAsync
@inject IAuthenticationService AuthenticationService;
@code {
private string? username;
private void LocalLoginChanged(string? name)
{
Logger.LogInformation("event firing!!!");
username = name;
StateHasChanged();
}
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Logger.LogInformation("user.razor initilised 1");
AuthenticationService.LoginChanged += LocalLoginChanged;
Logger.LogInformation("user.razor initilised 2");
}
// Don't forget to unsubscribe when the component is disposed
public void Dispose()
{
AuthenticationService.LoginChanged -= LocalLoginChanged;
}
}
评论
好的,所以我设法让它工作。我没有选择相同的名字,但我想你会明白的。
所以这是你的服务的代码
public delegate void AuthDelegate(string name);
public interface IEventTesterAuth
{
public event AuthDelegate? OnAuth;
public void FireEvent(string name);
}
public class EventTesterAuth: IEventTesterAuth
{
public event AuthDelegate? OnAuth;
public void FireEvent(string name)
{
OnAuth?.Invoke(name);
}
}
这是 Blazor 组件中的 c# 代码
private string _someName;
protected override void OnInitialized()
{
EvTeAu.OnAuth += AuthChanged;
base.OnInitialized();
}
public void FireInvoke()
{
EvTeAu.FireEvent("Johnson");
}
private async void AuthChanged(string name)
{
_someName = name;
await InvokeAsync(StateHasChanged);
}
这是测试它的 HTML 部分
<button @onclick="FireInvoke">Invoke</button>
<p role="status">Current name: @_someName</p>
这是注射
@inject IEventTesterAuth EvTeAu
这是在 Main 方法中添加的 Service
builder.Services.AddSingleton<IEventTesterAuth, EventTesterAuth>();
现在,我的主要变化是替换事件中的操作部分以委托,因为这就是我通常的做法。然后,我还确保您的StateHasChanged在InvokeAsync中被调用,因为没有它,页面通常不会更新。您可能仍然应该按照 Ale 的建议在某个时候使用 Dispose。但现在,这可以满足您的需求。
评论