События
Чемпионат мира Power BI DataViz
14 февр., 16 - 31 мар., 16
С 4 шансами войти, вы можете выиграть пакет конференции и сделать его в LIVE Grand Finale в Лас-Вегасе
ПодробнееЭтот браузер больше не поддерживается.
Выполните обновление до Microsoft Edge, чтобы воспользоваться новейшими функциями, обновлениями для системы безопасности и технической поддержкой.
Примечание
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 9 этой статьи.
Важно!
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 9 этой статьи.
Роберт Хакен
В этой статье объясняется, как избежать перезаписи параметров в приложениях Blazor во время rerendering.
Платформа Blazor обычно позволяет безопасно назначить параметр с родительского компонента на дочерний:
Дочерний компонент получает новые значения параметров, которые могут перезаписать существующие значения при повторной отрисовке родительского компонента. Случайно перезаписанные значения параметров в дочернем компоненте часто возникают при разработке компонента с одним или несколькими параметрами, привязанными к данным, а также если разработчик выполняет запись данных непосредственно в параметр в дочернем элементе:
Возможность перезаписи значений параметров также распространяется и на методы доступа свойства set
дочернего компонента.
Важно!
Мы не рекомендуем создавать компоненты, которые напрямую выполняют запись в собственные параметры после первой отрисовки.
Рассмотрим следующий компонент ShowMoreExpander
, который:
InitiallyExpanded
).После демонстрации переопределенного параметра с помощью следующего компонента ShowMoreExpander
демонстрируется правильный подход для этого сценария с помощью измененного компонента ShowMoreExpander
. Следующие примеры можно разместить в локальном примере приложения для ознакомления с описанным выше поведением.
ShowMoreExpander.razor
:
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private void ShowMore() => InitiallyExpanded = true;
}
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private void ShowMore() => InitiallyExpanded = true;
}
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private void ShowMore()
{
InitiallyExpanded = true;
}
}
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private void ShowMore()
{
InitiallyExpanded = true;
}
}
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private void ShowMore()
{
InitiallyExpanded = true;
}
}
<div @onclick="ShowMore" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @InitiallyExpanded)</h2>
</div>
@if (InitiallyExpanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private void ShowMore()
{
InitiallyExpanded = true;
}
}
Компонент ShowMoreExpander
добавляется в следующий родительский компонент Expanders
, который может вызывать StateHasChanged:
@onclick
кнопки подключает обработчик событий к событию onclick
кнопки. Обработка событий рассматривается более подробно в статье Обработка событий ASP.NET Core Blazor.Expanders.razor
:
@page "/expanders"
<PageTitle>Expanders</PageTitle>
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@page "/expanders"
<PageTitle>Expanders</PageTitle>
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@page "/expanders"
<PageTitle>Expanders</PageTitle>
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@page "/expanders"
<PageTitle>Expanders</PageTitle>
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@page "/expanders"
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@page "/expanders"
<h1>Expanders Example</h1>
<ShowMoreExpander InitiallyExpanded="false">
Expander 1 content
</ShowMoreExpander>
<ShowMoreExpander InitiallyExpanded="false" />
<button @onclick="StateHasChanged">Call StateHasChanged</button>
ShowMoreExpander
Изначально компоненты ведут себя независимо при установке их InitiallyExpanded
свойств. Дочерние компоненты сохраняют свои состояния, как и ожидалось.
При вызове StateHasChanged в родительском компоненте платформа Blazor повторно отрисовывает дочерние компоненты, если их параметры могли измениться:
Для компонента Expanders
:
ShowMoreExpander
компонент задает дочернее содержимое в потенциально изменяемом RenderFragmentрежиме, поэтому вызов StateHasChanged родительского компонента автоматически перезаписывает компонент и потенциально перезаписывает значение InitiallyExpanded
его первоначального false
значения.ShowMoreExpander
не задает дочернее содержимое. Поэтому потенциально изменяемый делегат RenderFragment не существует. Вызов StateHasChanged в родительском компоненте не активирует автоматическую повторную отрисовку дочернего компонента, поэтому значение компонента InitiallyExpanded
не перезаписывается.Чтобы сохранить состояние в предыдущем сценарии, используйте частное поле в компоненте ShowMoreExpander
для поддержания его состояния.
Следующий измененный компонент ShowMoreExpander
:
InitiallyExpanded
из родительского элемента.expanded
) в событии OnInitialized
.Примечание
Рекомендации в этом разделе распространяются на аналогичную логику методов доступа set
параметров компонентов, что может приводить к аналогичным нежелательным побочным эффектам.
ShowMoreExpander.razor
:
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
protected override void OnInitialized() => expanded = InitiallyExpanded;
private void Expand() => expanded = true;
}
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
protected override void OnInitialized() => expanded = InitiallyExpanded;
private void Expand() => expanded = true;
}
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
protected override void OnInitialized()
{
expanded = InitiallyExpanded;
}
private void Expand()
{
expanded = true;
}
}
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
protected override void OnInitialized()
{
expanded = InitiallyExpanded;
}
private void Expand()
{
expanded = true;
}
}
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
protected override void OnInitialized()
{
expanded = InitiallyExpanded;
}
private void Expand()
{
expanded = true;
}
}
<div @onclick="Expand" class="card bg-light mb-3" style="width:30rem">
<div class="card-header">
<h2 class="card-title">Show more (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
private bool expanded;
[Parameter]
public bool InitiallyExpanded { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
protected override void OnInitialized()
{
expanded = InitiallyExpanded;
}
private void Expand()
{
expanded = true;
}
}
Примечание
Измененный ShowMoreExpander
параметр не отражает изменения InitiallyExpanded
параметра после инициализации (OnInitialized
). В некоторых сценариях уже инициализированный компонент может получать новые значения параметров. Это может произойти, например, в основном подчиненном представлении, где один и тот же компонент используется для отображения разных представлений подробностей или при /item/{id}
изменении параметра маршрута для отображения другого элемента.
Рассмотрим следующий ToggleExpander
компонент:
ToggleExpander.razor
:
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet() => expanded = Expanded;
private async Task Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet() => expanded = Expanded;
private async Task Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet()
{
expanded = Expanded;
}
private async Task Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment? ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet()
{
expanded = Expanded;
}
private async Task Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet()
{
expanded = Expanded;
}
private async Task Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
<div class="card bg-light mb-3" style="width:30rem">
<div @onclick="Toggle" class="card-header">
<h2 class="card-title">Toggle (<code>Expanded</code> = @expanded)</h2>
</div>
@if (expanded)
{
<div class="card-body">
<p class="card-text">@ChildContent</p>
</div>
}
</div>
@code {
[Parameter]
public bool Expanded { get; set; }
[Parameter]
public EventCallback<bool> ExpandedChanged { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private bool expanded;
protected override void OnParametersSet()
{
expanded = Expanded;
}
private async Task Toggle()
{
expanded = !expanded;
await ExpandedChanged.InvokeAsync(expanded);
}
}
Компонент ToggleExpander
должен использоваться с синтаксисом @bind-Expanded="{field}"
привязки, позволяя двусторонней синхронизации параметра.
ExpandersToggle.razor
:
@page "/expanders-toggle"
<PageTitle>Expanders Toggle</PageTitle>
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle() => expanded = !expanded;
}
@page "/expanders-toggle"
<PageTitle>Expanders Toggle</PageTitle>
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle() => expanded = !expanded;
}
@page "/expanders-toggle"
<PageTitle>Expanders Toggle</PageTitle>
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle()
{
expanded = !expanded;
}
}
@page "/expanders-toggle"
<PageTitle>Expanders Toggle</PageTitle>
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle()
{
expanded = !expanded;
}
}
@page "/expanders-toggle"
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle()
{
expanded = !expanded;
}
}
@page "/expanders-toggle"
<h1>Expanders Toggle</h1>
<ToggleExpander @bind-Expanded="expanded">
Expander content
</ToggleExpander>
<button @onclick="Toggle">Toggle</button>
<button @onclick="StateHasChanged">Call StateHasChanged</button>
@code {
private bool expanded;
private void Toggle()
{
expanded = !expanded;
}
}
Дополнительные сведения о привязке родительского дочернего объекта см. в следующих ресурсах:
Дополнительные сведения об обнаружении изменений, включая сведения о точных типах, которые Blazor проверяются, см. в ASP.NET отрисовке основных Razor компонентов.
Отзыв о ASP.NET Core
ASP.NET Core — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв:
События
Чемпионат мира Power BI DataViz
14 февр., 16 - 31 мар., 16
С 4 шансами войти, вы можете выиграть пакет конференции и сделать его в LIVE Grand Finale в Лас-Вегасе
ПодробнееОбучение
Модуль
Взаимодействие с данными в веб-приложениях Blazor - Training
Узнайте, как создать графический пользовательский интерфейс в веб-приложении Blazor путем создания и сборки компонентов Blazor. Доступ к данным и предоставление общего доступа к ним для отображения на нескольких страницах в приложении.