Вопрос или проблема
У меня есть компонент всплывающего окна, который оборачивает базовый компонент всплывающего окна, который оборачивает DxPopup
(DevExpress). С двусторонним связыванием данных я ожидал, что значения свойств будут передаваться не только от родителя к ребенку, но и от ребенка к родителю. Правильно ли это ожидание? Вот мой код:
PopupBase.razor
@using DevExpress.Blazor
<DxPopup @bind-Visible="Visible">
</DxPopup>
@code {
[Parameter]
public bool Visible { get; set; }
[Parameter]
public EventCallback<bool> VisibleChanged { get; set; }
}
DetailPopup.razor
<PopupBase @bind-Visible="Visible">
</PopupBase>
@code {
[Parameter]
public bool Visible { get; set; }
[Parameter]
public EventCallback<bool> VisibleChanged { get; set; }
}
Page.razor
<DxButton Text="Показать всплывающее окно" Click="@ShowPopup" />
<DetailPopup @bind-Visible="showPopup" />
@code {
bool showPopup = false;
void ShowPopup()
{
showPopup = true;
}
}
@bind-Visible
должен включать двустороннее связывание и автоматически использовать события VisibleChanged
для передачи значений параметров вверх к родителям, верно? Или нет? Должны ли параметры у родителей автоматически обновляться? Или мне нужно переключиться на @bind-Visible:get/set
, чтобы добиться желаемого. Но даже с этим я читал, что нам не следует перезаписывать значения параметров, так что это также оставляет меня в недоумении.
Проблема в том, что если видимость не установлена правильно, то мы можем получить несколько всплывающих окон на экране (из разных компонентов).
Ответ или решение
Двусторонняя привязка данных в Blazor: Проблема с распространением данных в компоненте Popup
При разработке приложений на Blazor, важно правильно понимать механизмы двусторонней привязки данных, особенно когда мы имеем дело с компонентами, обрабатывающими состояние, такими как окна (попапы). Ваш код предоставляет интересный случай, в котором вы сталкиваетесь с вопросами о том, как параметры взаимодействуют друг с другом в системе компонентов.
Проблема с ожиданиями двусторонней привязки
Исходя из представленного вами кода, вы ожидаете, что при изменении свойства Visible
в дочернем компоненте PopupBase
, оно должно автоматически обновлять значение в родительском компоненте (DetailPopup
), а затем и в конечном Page
. Однако поведение, которое вы наблюдаете, может показаться неожиданным, если вы не совсем точно следуете правилам Blazor о том, как работает событие VisibleChanged
.
Основная проблема
Когда вы используете директиву @bind-Visible
, Blazor устанавливает связь, которая включает:
- Привязку значения свойства (
Visible
) из родителя в дочерний компонент. - Событие
VisibleChanged
, которое должно срабатывать в дочернем компоненте, когда значение изменяется, чтобы обновить родителя.
Вы указали, что ваш компонент PopupBase
не вызывает VisibleChanged
, когда происходит изменение состояния Visible
. Это, возможно, и является корнем проблемы.
Как исправить?
Для того чтобы двусторонняя привязка работала корректно, вам необходимо вручную вызывать VisibleChanged
в PopupBase
, когда значение видимости изменяется. Вот как можно сделать это:
-
Измените свойство
Visible
в компонентеPopupBase
так, чтобы оно использовало метод-сеттер. -
Вызывайте
VisibleChanged.InvokeAsync(value)
в сеттере при изменении видимости.
Вот переработанный код для PopupBase.razor
:
@using DevExpress.Blazor
<DxPopup @bind-Visible="Visible">
</DxPopup>
@code {
private bool visible;
[Parameter]
public bool Visible
{
get => visible;
set
{
if (visible != value)
{
visible = value;
VisibleChanged.InvokeAsync(value);
}
}
}
[Parameter]
public EventCallback<bool> VisibleChanged { get; set; }
}
Изменения в детализированном попапе
В DetailPopup.razor
нет необходимости вносить изменения, если вы правильно передали параметры и события из PopupBase
.
Резюме
Использование двусторонней привязки в Blazor требует четкого понимания того, как событие VisibleChanged
должно быть вызвано, чтобы оно корректно обновляло родительские компоненты. Просто указание на @bind-Visible
не гарантирует, что обновление будет происходить автоматически, если вы не реализуете вызов события в своем дочернем компоненте.
При применении этих изменений вы сможете избежать ситуаций с отображением нескольких попапов на экране, так как состояние будет корректно синхронизироваться во всей вашей иерархии компонентов.