更好的作用域服务实现:
public class CurrentPage
{
public string CurrentPageName { get; private set; }
public void SetCurrentPageName(string name)
{
if (!string.Equals(CurrentPageName, name))
{
CurrentPageName = name;
NotifyStateChanged();
}
}
public event Action OnChange;
private void NotifyStateChanged() => OnChange?.Invoke();
}
我们没有传递对象字典,而是有一个只做一件事情的简单服务。改变页面的唯一方法是调用 SetCurrentPageName
,这将引发一个事件来让消费者知道名称已更改。在未嵌套的组件之间,这是必需的,因为更新否则不会传播。
我们还需要在启动时注册服务(作为范围,因为当前页面是特定于会话的):
services.AddScoped<CurrentPage>()
我们将在
Index.razor
中注入并使用它:
@page "/"
@inject CurrentPage currentPage
<h1>Hello, world!</h1>
Welcome to your new app.
<button @onclick="ChangeName">Set Page Name</button>
<SurveyPrompt Title="How is Blazor working for you?" />
@code
{
protected override void OnInitialized()
{
currentPage.SetCurrentPageName("The Home Page");
base.OnInitialized();
}
void ChangeName() => currentPage.SetCurrentPageName("Name changed");
}
最后,在 NavMenu.razor
的顶部:
@inject CurrentPage currentPage
and further down..
<p>The current page is @currentPage.CurrentPageName</p>
@code {
protected override void OnInitialized()
{
currentPage.OnChange += () => StateHasChanged();
base.OnInitialized();
}
这个状态类并不知道它是如何被使用的,并且没有对象或引用被传递。
[编辑] 我决定注入/覆盖模式来设置页面名称相当不符合Blazor的风格,所以我还编写了一个组件来简化这个过程 - PageName.razor:
@inject CurrentPage currentPage;
@code {
[Parameter]
public string Name { get; set; }
protected override void OnParametersSet()
{
currentPage.SetCurrentPageName(Name);
}
}
现在任何想要设置标题的页面都可以这样做:
@page "/fetchdata"
@inject HttpClient Http
<PageName Name="Weather forecast page!" />
整个消费者现在已经成为一个组件 :)