C# 在EventHandler中调用this.StateHasChanged

C# 在EventHandler中调用this.StateHasChanged,c#,razor,.net-core,blazor,blazor-server-side,C#,Razor,.net Core,Blazor,Blazor Server Side,我有以下问题。 我创建了一个事件并订阅了它,现在我想在事件触发时更改UI using System; using MintWebApp.Data; using MintWebApp.Models; using Microsoft.AspNetCore.Components; namespace WebApp.UI.Core { public partial class AppHeader { public string status { get; se

我有以下问题。 我创建了一个事件并订阅了它,现在我想在事件触发时更改UI

 using System;
 using MintWebApp.Data;
 using MintWebApp.Models;
 using Microsoft.AspNetCore.Components;
 namespace WebApp.UI.Core
 {
    public partial class AppHeader
    {
        public string status { get; set; }
        [Inject]
        public StateService state { get; set; }

        EventHandler<string> onStatusChanged= (sender, eventArgs) => {

            //Here i get the error, I can't access this and status
            status = eventArgs;
            this.StateHasChanged();
            Console.WriteLine(eventArgs.PatientName);
        };

        protected override void OnInitialized() => state.StatusHandler += onStatusChanged;
    }

}
使用系统;
使用MintWebApp.Data;
使用MintWebApp.Models;
使用Microsoft.AspNetCore.Components;
命名空间WebApp.UI.Core
{
公共部分类AppHeader
{
公共字符串状态{get;set;}
[注入]
公共状态服务状态{get;set;}
EventHandler onStatusChanged=(发送方,eventArgs)=>{
//在这里我得到了错误,我无法访问此和状态
状态=事件参数;
此.StateHasChanged();
Console.WriteLine(eventArgs.PatientName);
};
受保护的覆盖void OnInitialized()=>state.StatusHandler+=onStatusChanged;
}
}
我得到这个错误 字段初始值设定项无法引用非静态字段、方法或属性“AppHeader.patientContext”

关键字“this”在当前上下文中不可用


如何订阅一个事件并更新UI

由于这里的
EventHandler
类型无法按预期工作,因此需要以稍微不同的方式处理此问题。(至少对我来说不是)

首先,对于
EventArgs
,请记住这是一种类型,因此您不能在没有强制转换的情况下将它们分配给
Status
属性(作为字符串)。实现这一点的方法是定义您自己的参数类型,该类型派生自EventArgs,如下所示:

公共类PatientEventArgs:EventArgs
{
公共字符串PatientName{get;set;}
公共字符串状态值{get;set;}
}
接下来,对于需要使用的handler方法,将其设置为异步方法。我发现异步非常重要,因此您可以使用
InvokeAsync
,避免线程和调度程序不一致时出现异常,就像在其他打开的窗口或其他用户在其他地方登录时一样,通过以下帖子:

private async void OnStatusChanged(对象发送方,事件参数e){
//确保参数是您期望的类型
if(e.GetType()==typeof(PatientEventArgs))
//强制转换为正确的参数类型以访问属性
var patientStatus=e作为PatientEvendArgs;
status=patientStatus.StatusValue;
Console.Writeline(patientStatus.patientsname);
/*将InvokeAsync方法与wait一起使用以确保
StateHasChanged在此正确运行,而不会干扰另一个
线程(打开窗口或其他用户)*/
等待InvokeAsync(()=>StateHasChanged());
}
接下来,对于您的场景来说,important,由于需要实现
IDisposable
,以便在组件拆下后进行清理,因此您将使用部分类声明碰壁。相反,使用如下继承结构,并使用OnInitialized和Dispose覆盖

AppHeader.razor.cs

公共类AppHeaderBase:OwningComponentBase
{
//如上所述的OnStatusChanged方法
protected override void OnInitialized()//也可以使用异步版本
{
//取消订阅一次以确保只连接一次
//防止事件传播
//如果此组件未订阅,则不会执行任何操作
state.StatusHandler-=onStatusChanged;
//订阅活动
state.StatusHandler+=onStatusChanged;
}
受保护的覆盖无效处置(布尔处置)
{
//在拆卸时取消订阅,防止事件传播和内存泄漏
state.StatusHandler-=onStatusChanged;
} 
}
这利用了
OwningComponentBase
中的一些内置Blazor功能,包括
Dispose
方法,同时为您更好地管理依赖注入

进一步阅读(注意,对于这个示例,我没有深入讨论这个问题,因为它使用了单例,但值得一读,以理解Blazor中的DI生命周期)

然后在你的AppHeader.razor中

。。。。
@继承AppHeaderBase
....
现在,当您从其他地方使用
StateService
中的事件处理程序时,使用需要传递的值构建一个新的
PatientEventArgs
类型:

var newArgs=new PatientEventArgs(){
PatientName=“SomeName”,
StatusValue=“SomeStatus”
};
并根据需要在代码中传递:

state.OnStatusChanged(this,newArgs);
或直接从Razor语法:

Sender按钮
这将根据需要多播您的事件,所有订阅者都将接收并更新它


,改编自我一直在研究的另一个版本。

这需要以稍微不同的方式进行处理,因为
事件处理程序类型在这里无法按预期工作。(至少对我来说不是)

首先,对于
EventArgs
,请记住这是一种类型,因此您不能在没有强制转换的情况下将它们分配给
Status
属性(作为字符串)。实现这一点的方法是定义您自己的参数类型,该类型派生自EventArgs,如下所示:

公共类PatientEventArgs:EventArgs
{
公共字符串PatientName{get;set;}
公共字符串状态值{get;set;}
}
接下来,对于需要使用的handler方法,将其设置为异步方法。我发现异步非常重要,因此您可以使用
InvokeAsync
,避免线程和调度程序不一致时出现异常,就像在其他打开的窗口或其他用户在其他地方登录时一样,通过以下帖子:

private async void OnStatusChanged(对象发送方,事件参数e){
//确保参数是您期望的类型
if(e.GetType()==typeof(PatientEventArgs))
//强制转换为正确的参数类型以访问属性
v