Blazor:更改边界 属性 不会更新视图
Blazor: Changing bound property does not update the view
我在 Blazor(服务器端)中有一个带有 InputText 控件的 EditForm。表单绑定到模型 class,InputText 字段绑定到由本地存储支持的单个 属性。
页面加载时,InputText 显示空白值。我调用 InitAsync 方法从本地存储异步加载数据。这有效,但是使用加载的数据设置 属性 不会更新视图。
如果我将值绑定到具有单向绑定的 span 标记而不是 InputText(具有双向绑定),则会出现同样的问题。
从存储中异步加载数据后如何让视图更新?
View/component class:
@inject Blazored.LocalStorage.ILocalStorageService localStorage
<EditForm Model="@model" class="pl-4 pr-3 py-1 loginform" OnValidSubmit="@HandleValidSubmit">
<span>model.OperID</span>
<InputText class="form-control mr-sm-2" style="width: 158px" placeholder="OperID" @bind-Value="@model.OperID"></InputText>
<button class="btn btn-success oi oi-account-login" @onclick="Login"></button>
</EditForm>
@code {
private Models.MainModel model = new Models.MainModel();
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await model.InitializeAsync(localStorage);
}
void Login()
{
}
private void HandleValidSubmit()
{
Console.WriteLine("OnValidSubmit");
}
}
型号class:
public class MainModel
{
Blazored.LocalStorage.ILocalStorageService? localStorage;
public MainModel()
{
}
public async Task InitializeAsync(Blazored.LocalStorage.ILocalStorageService localStorage)
{
this.localStorage = localStorage;
if (localStorage != null)
{
// the value loads correctly, but setting the property does not cause the view to update as it should.
// ConfigureAwait(false) makes no difference...
OperID = await localStorage.GetItemAsync<string?>("OperID").ConfigureAwait(false);
}
}
string? operID = "DUMMY"; // null;
public string? OperID
{
get
{
return operID;
}
set
{
operID = value;
if (localStorage != null)
{
localStorage.SetItemAsync("OperID", value);
}
}
}
}
由于您使用的是服务器端 Blazor,并且预渲染设置可能处于活动状态,因此您不能也不应该使用 OnIntialized 或 OnInitializedAsync 方法。相反,您应该使用 OnAfterRenderAsync 方法,这是使用 JSInterop 的合适位置。你的代码应该包含在一个 if 语句中,检查这是否是第一次渲染,像这样:
protected override async Task OnAfterRenderAsync(bool firstRender)
{ if( firstRender)
{
await model.InitializeAsync(localStorage);
// And of course the StateHasChanged method should be called here to refresh the page.
StateHasChanged();
}
}
这样您的模型只会被初始化一次,而不是每次执行 OnAfterRenderAsync 时,也就是页面组件需要重新呈现时。
注意:如果您正在重新渲染,则根本不会调用 OnAfterRenderAsync 方法。
_Host.cshtml 中的以下代码片段可以判断您是否正在使用预渲染:
<app>
<component type="typeof(App)" render-mode="ServerPrerendered" />
</app>
正如您从设置中看到的那样,您的应用正在服务器上预呈现。
Blazored.LocalStorage 是否支持数据保护,如果不支持。使用 Blazor 团队创建的库。
这是我为使其生效而更改的代码:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender) // prevent infinite loop
{
await model.InitializeAsync(localStorage); // load data
StateHasChanged(); // update view
}
}
我在 Blazor(服务器端)中有一个带有 InputText 控件的 EditForm。表单绑定到模型 class,InputText 字段绑定到由本地存储支持的单个 属性。
页面加载时,InputText 显示空白值。我调用 InitAsync 方法从本地存储异步加载数据。这有效,但是使用加载的数据设置 属性 不会更新视图。
如果我将值绑定到具有单向绑定的 span 标记而不是 InputText(具有双向绑定),则会出现同样的问题。
从存储中异步加载数据后如何让视图更新?
View/component class:
@inject Blazored.LocalStorage.ILocalStorageService localStorage
<EditForm Model="@model" class="pl-4 pr-3 py-1 loginform" OnValidSubmit="@HandleValidSubmit">
<span>model.OperID</span>
<InputText class="form-control mr-sm-2" style="width: 158px" placeholder="OperID" @bind-Value="@model.OperID"></InputText>
<button class="btn btn-success oi oi-account-login" @onclick="Login"></button>
</EditForm>
@code {
private Models.MainModel model = new Models.MainModel();
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await model.InitializeAsync(localStorage);
}
void Login()
{
}
private void HandleValidSubmit()
{
Console.WriteLine("OnValidSubmit");
}
}
型号class:
public class MainModel
{
Blazored.LocalStorage.ILocalStorageService? localStorage;
public MainModel()
{
}
public async Task InitializeAsync(Blazored.LocalStorage.ILocalStorageService localStorage)
{
this.localStorage = localStorage;
if (localStorage != null)
{
// the value loads correctly, but setting the property does not cause the view to update as it should.
// ConfigureAwait(false) makes no difference...
OperID = await localStorage.GetItemAsync<string?>("OperID").ConfigureAwait(false);
}
}
string? operID = "DUMMY"; // null;
public string? OperID
{
get
{
return operID;
}
set
{
operID = value;
if (localStorage != null)
{
localStorage.SetItemAsync("OperID", value);
}
}
}
}
由于您使用的是服务器端 Blazor,并且预渲染设置可能处于活动状态,因此您不能也不应该使用 OnIntialized 或 OnInitializedAsync 方法。相反,您应该使用 OnAfterRenderAsync 方法,这是使用 JSInterop 的合适位置。你的代码应该包含在一个 if 语句中,检查这是否是第一次渲染,像这样:
protected override async Task OnAfterRenderAsync(bool firstRender)
{ if( firstRender)
{
await model.InitializeAsync(localStorage);
// And of course the StateHasChanged method should be called here to refresh the page.
StateHasChanged();
}
}
这样您的模型只会被初始化一次,而不是每次执行 OnAfterRenderAsync 时,也就是页面组件需要重新呈现时。
注意:如果您正在重新渲染,则根本不会调用 OnAfterRenderAsync 方法。
_Host.cshtml 中的以下代码片段可以判断您是否正在使用预渲染:
<app>
<component type="typeof(App)" render-mode="ServerPrerendered" />
</app>
正如您从设置中看到的那样,您的应用正在服务器上预呈现。 Blazored.LocalStorage 是否支持数据保护,如果不支持。使用 Blazor 团队创建的库。
这是我为使其生效而更改的代码:
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender) // prevent infinite loop
{
await model.InitializeAsync(localStorage); // load data
StateHasChanged(); // update view
}
}