dependency-injection - Blazor:如何使用来自具有 2 个不同状态的 2 个不同页面的组件
问题描述
在 Blazor 应用程序中,我想使用来自两个不同页面的组件。组件使用服务来维护其状态。但是每个页面都需要让组件使用不同的状态。以下是我认为我会这样做的方式(使用默认的 Counter 组件进行演示)。
CounterService.cs
namespace TestTwoInterfaceToOneService.Shared
{
public interface ICounterServiceA
{
int CurrentCount { get; set; }
void IncrementCount();
}
public interface ICounterServiceB
{
int CurrentCount { get; set; }
void IncrementCount();
}
public class CounterService : ICounterServiceA, ICounterServiceB
{
public int CurrentCount { get; set; }
public void IncrementCount()
{
CurrentCount++;
}
}
}
在 Program.cs 添加:
builder.Services.AddScoped<ICounterServiceA, CounterService>();
builder.Services.AddScoped<ICounterServiceB, CounterService>();
反剃刀
<h1>Counter</h1>
<p>Current count: @CounterService.CurrentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
[Parameter]
public CounterService CounterService { get; set; }
private void IncrementCount()
{
CounterService.CurrentCount++;
}
}
PageA.razor
@page "/pagea"
@inject ICounterServiceA CounterServiceA
<h3>Page A</h3>
<Counter CounterService="CounterServiceA" /> @*<-- Error: Cannot convert from ICounterServiceB to CounterService*@
PageB.razor
@page "/pageb"
@inject ICounterServiceB CounterServiceB
<h3>Page B</h3>
<Counter CounterService="CounterServiceB" /> @*<-- Error: Cannot convert from ICounterServiceB to CounterService*@
当我尝试将服务传递给组件时,我收到错误“无法从 ICounterServiceB 转换为 CounterService”。我发现使用 2 个指向相同具体实现的相同接口确实给了我 2 个作用域实例。但是,我无法弄清楚如何将这些实例传递给组件。
有没有我遗漏的部分?或者,这应该以其他方式完成吗?
解决方案
结合 Henk 的回答和 Brian 的评论,我想出的解决方案是:
CounterService.cs
namespace TestTwoInterfaceToOneService.Shared
{
public class CounterService
{
public int CurrentCount { get; set; }
public void IncrementCount()
{
CurrentCount++;
}
public void ResetCount()
{
CurrentCount = 0;
}
}
}
CounterStateService.cs
using System.Collections.Generic;
namespace TestTwoInterfaceToOneService.Shared
{
public interface ICounterStateService
{
CounterService this[string key] { get; }
}
public class CounterStateService : ICounterStateService
{
private Dictionary<string, CounterService> counterServices = new();
public CounterService this[string key]
{
get
{
if (!counterServices.ContainsKey(key))
{
counterServices.Add(key, new CounterService());
}
return counterServices[key];
}
}
}
}
在 Program.cs 中,添加
builder.Services.AddScoped<ICounterStateService, CounterStateService>();
反剃刀
<p>Current count: @CounterService.CurrentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Increment</button>
@code {
[Parameter]
public CounterService CounterService { get; set; }
private void IncrementCount()
{
CounterService.CurrentCount++;
}
}
PageA.razor
@page "/pagea"
@inject ICounterStateService CounterStateService
<h3>Page A</h3>
<Counter CounterService='CounterStateService["A"]' />
<button class="btn btn-primary" @onclick='CounterStateService["A"].ResetCount'>Reset Count</button>
PageB.razor
@page "/pageb"
@inject ICounterStateService CounterStateService
<h3>Page B</h3>
<Counter CounterService='CounterStateService["B"]' />
<button class="btn btn-primary" @onclick='CounterStateService["B"].ResetCount'>Reset Count</button>
解决方案
或者,这应该以其他方式完成吗?
是的。将这种使用模式烘焙到 Type 结构中不会很好地适应或扩展。如果您需要第三页,或者想让它动态化怎么办?
您可以使用包装服务和带有键的方案将状态绑定到组件:
public class CounterService { ... } // no need to register
public class CounterStateService // register for injection
{
private Dictionary <string, CounterService> stateLookup = new();
public CounterService this[string key]
{
if (! stateLookup.tryGetValue (key, out CounterService service))
{
service = new CounterService();
stateLookup.Add(key, service);
}
return service;
}
}
并像使用它一样
@page "/pagea"
@inject CounterStateService CounterStateService
<h3>Page A</h3>
<Counter CounterService="CounterStateService["A"]" />
推荐阅读
- java - 按钮的 Javafx BackgroundImage 不起作用
- windows - 上传文件到客户端服务器
- r - 绘制 x 轴范围从 17:30 到 7:30 的时间值直方图
- laravel - MacOS(Docker)上的 Laravel Brower 测试(Dusk)错误:无法在 localhost 端口 9515 上连接:连接被拒绝
- ios - 如何根据布尔值的结果运行 if else 函数
- scala - 使用子类的类型实现 trait 方法
- php - 我可以只在一个重定向中管理 https、www 和没有 .php 重定向吗?
- jstl - 使用 JSTL 计算两个日期之间的天数差
- node.js - 在控制台中安装 jest 时出错
- c# - 无法通过 ASP.NET Core 中的 JQuery ActionResult 调用加载部分视图