Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/css/38.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mvvm 为每个Blazor回路创建一次对象(ViewModel)_Mvvm_Dependency Injection_Viewmodel_Blazor_Circuit - Fatal编程技术网

Mvvm 为每个Blazor回路创建一次对象(ViewModel)

Mvvm 为每个Blazor回路创建一次对象(ViewModel),mvvm,dependency-injection,viewmodel,blazor,circuit,Mvvm,Dependency Injection,Viewmodel,Blazor,Circuit,我目前正在编写一个小型Blazor Web UI。我正在尝试采用/实现MVVM模式。为此,我创建了两个组件基类。一个只处理Blazor生命周期方法(添加一些异常处理),另一个根据这些生命周期方法的执行处理ViewModel初始化。该组件还实现IDisposable接口,当组件不可见时,Blazor会自动调用该接口 下面是我的WebComponentBase类和ViewModelAwareComponent类的代码片段,大致介绍一下该模式: 公共抽象类WebFpComponentBase:Com

我目前正在编写一个小型Blazor Web UI。我正在尝试采用/实现MVVM模式。为此,我创建了两个组件基类。一个只处理Blazor生命周期方法(添加一些异常处理),另一个根据这些生命周期方法的执行处理ViewModel初始化。该组件还实现IDisposable接口,当组件不可见时,Blazor会自动调用该接口

下面是我的WebComponentBase类和ViewModelAwareComponent类的代码片段,大致介绍一下该模式:


公共抽象类WebFpComponentBase:ComponentBase、IDisposable、IHtmlStyles
{
private const string DEFAULT\u DIM\u VALUE=“auto”;
[注入]
受保护的IEExceptionUIHandler异常处理程序{get;set;}
//为简洁起见,省略了字段和参数
#区域Blazor组件生命周期
/// 
///当组件接收到所有初始参数时,在OnInitialized之后调用OnInitialized。将所有异步操作放在此处,
///这需要组件重新渲染。
/// 
/// 
受保护的重写异步任务OnInitializedAsync()
{
尝试
{
wait base.OnInitializedAsync();
_Info($“{nameof(OnInitializedAsync)}-在${this.GetType().FullName}类型的组件中调用的方法”);
等待OnInitializedInternalAsync();
_logger.Info($“{nameof(OnInitializedAsync)}-方法在${this.GetType().FullName}类型的组件中完成);
}捕获(例外情况除外)
{
//如果发生异常,则使用AfterRenderAsync()方法中的IEExceptionUIHandler阻止异常
_forwardException=ex;
_logger.Error($“{nameof(OnInitializedAsync)}:捕获和转发类型为{u forwardException.GetType().FullName}的异常”;
}
}
受保护的抽象任务OnInitializedInternalAsync();
//为简洁起见,省略了该类的其他方法
}
接下来是我的ViewModelAwareComponent,它确实有一个包含ViewModel的属性,并通过实现[BlazorLifecycleMethod]内部抽象方法自动启动ViewModel初始化和反初始化(关闭任何服务连接、重置任何值等)

公共抽象类ViewModelAwareComponent:WebFpComponentBase其中TViewModel:BaseViewModel
{
专用记录器_Logger=LogManager.GetCurrentClassLogger();
[参数]
公共虚拟TViewModel ViewModel{get;set;}
受保护的重写异步任务OnInitializedInternalAsync()
{
等待ViewModel.InitializeAsync();
ViewModel.PropertyChanged+=this.FireComponentState已更改;
}
公共重写异步void Dispose()
{
base.Dispose();
等待ViewModel.DeactivateAsync();
}
受保护的虚拟异步void FireComponentState已更改(对象发送方,PropertyChangedEventArgs e)
{
_Trace($“FireComponentStateShasChanged:属性{e.PropertyName}已更改!”);
等待InvokeAsync(this.StateHasChanged);
}
受保护的重写异步任务OnParametersSetAsyncInternal()
{
if(ViewModel==null)
{
抛出新ArgumentNullException($“{nameof(ViewModel)}”,“必须提供参数!”);
}
}
}
BaseViewModel类型仅实现以典型方式更改的InotifyProperty。我有一个“MainViewModel”,在整个连接(Blazor电路)中只应实例化一次。因此,我通过
Startup.cs
中的
services.addScope()
添加了它。因为它没有绑定到任何特定组件,所以我将它注入到我的
MainLayout.razor
中,这是我编写的每个razor组件的布局

布局在InitializedAsync()上实现了
受保护的覆盖异步任务
,如下所示:

受保护的重写异步任务OnInitializedAsync()
{
MainViewModel.PropertyChanged+=(obj,args)=>InvokeAsync(StateHasChanged);
等待MainViewModel.InitializeAsync();
//后来发生了一些其他事情
}
我现在的问题是,每次启动应用程序时都会进行两次初始化,而不是每次连接一次。去初始化也是如此,因为组件的Dispose()也被调用了两次。

调试时,我注意到在两个现有页面(路由组件)之间切换时,不会重新调用
OnInitializedAsync
。启动时只调用两次

你对这种行为有什么建议吗?是否有更好的方法来实现MainViewModel的预期行为

致以最良好的祝愿


tilt

由dani herrera的评论回答:


也许是关于预渲染?请看我的回答:

通过更改属性禁用预渲染

@(等待Html.RenderComponentAsync(RenderMode.ServerPrerendered))

@(等待Html.RenderComponentAsync(RenderMode.Server))

现在MainLayout.razor的OnInitializedAsync()只被调用了一次。

我看到这一点得到了回答,但我们也通过编写一个小型Blazor回路处理程序,然后将返回的回路id映射到一个作用域会话服务来实现这一点。创建(或断开/重新连接)新回路时,回路处理程序提供事件


为什么要调用
wait MainViewModel.InitializeAsync()在布局中
OnInitializedAsync
?可能是关于预渲染的?请看我的回答:@aguafrommars MainViewModel确实拥有WCF服务连接,必须先建立连接,然后应用程序才能启动。作为V