Я разрабатываю приложение Blazor WebAssembly, в котором у меня есть родительский компонент Father, содержащий два дочерних компонента (Child1 и Child2). Child2 следует включать только при выполнении определенного условия в Child1, но я сталкиваюсь с проблемами с поддержанием правильного состояния между этими компонентами.
В Child1 у меня есть компонент автозаполнения MudAutocomplete, который при выборе должен включать определенные функции в Child2, устанавливая состояние Model.SuperUser в родительском компоненте Father. Я позаботился о том, чтобы StateHasChanged() вызывался после обновления состояния в Child1, но ввод в Child2 оставался отключенным, даже если условие Model.SuperUser != null выполнено.
@page "/father"
<Child1 Model = "model" />
<Child2 Model = "model" />
@code {
private MyModel model;
protected override void OnInitialized()
{
model = new MyModel();
base.OnInitialized();
}
public class MyModel
{
public int? AdminUserId { get; set; }
public UserDTO? AdminUser { get; set; }
public int? CustomerUserId { get; set; }
public UserDTO? CustomerUser { get; set; }
public int? SuperUserId { get; set; }
public UserDTO? SuperUser { get; set; }
}
}
// Child1.razor
<!-- SuperUser -->
<div class = "form-group col-6">
<label class = "required" for = "SuperUser">@Localizer["SuperUser"]</label>
<MudAutocomplete T = "UserDTO"
ResetValueOnEmptyText = "true"
SearchFunc = "@SearchSuperUser"
ToStringFunc = "@(e => e == null ? null : $"{e.Email}")"
ShowProgressIndicator = "true"
Variant = "Variant.Outlined"
Clearable = "true"
Placeholder = "@Localizer["PleaseSelectSuperUser"]"
OnClearButtonClick = "OnSuperUserCleared"
ProgressIndicatorColor = "Color.Primary"
ValueChanged = "OnSuperUserValueChanged">
<NoItemsTemplate>
<MudList Clickable = "false">
<MudListItem>
@Localizer["NoItemsWasFound"]
</MudListItem>
</MudList>
</NoItemsTemplate>
<BeforeItemsTemplate>
<MudText Color = "Color.Primary" Class = "mud-list-item mud-list-item-gutters mud-list-item-clickable mud-ripple">@Localizer["PleaseSelectSuperUser"]</MudText>
</BeforeItemsTemplate>
<ProgressIndicatorInPopoverTemplate>
<MudList Clickable = "false">
<MudListItem>
@Localizer["Loading"]
</MudListItem>
</MudList>
</ProgressIndicatorInPopoverTemplate>
</MudAutocomplete>
<ValidationMessage For = "@(() => Model.SuperUserId)" />
</div>
@code {
[Parameter][EditorRequired] public MyModel Model { get; set; } = null!;
private async Task<IEnumerable<UserDTO>> SearchSuperUser(string value)
{
var result = await _myService.GetSuperUserFiltered(value);
if (result != null)
{
return result;
}
return new List<UserDTO>();
}
private void OnSuperUserCleared(MouseEventArgs args)
{
Model.SuperUser = null;
Model.SuperUserId = null;
StateHasChanged();
}
private void OnSuperUserValueChanged(UserDTO value)
{
Model.SuperUser = value;
Model.SuperUserId = value.Id;
StateHasChanged();
}
}
// Child2.razor
<!-- AdminUser -->
<div class = "form-group col-6">
<label class = "required" for = "AdminUser">@Localizer["AdminUser"]</label>
<MudAutocomplete T = "UserDTO"
ResetValueOnEmptyText = "true"
SearchFunc = "@SearchAdminUser"
ToStringFunc = "@(e => e == null ? null : $"{e.Email}")"
ShowProgressIndicator = "true"
Variant = "Variant.Outlined"
Clearable = "true"
Placeholder = "@Localizer["PleaseSelectAdminUser"]"
OnClearButtonClick = "OnAdminUserCleared"
ProgressIndicatorColor = "Color.Primary"
ValueChanged = "OnAdminUserValueChanged"
Disabled = "Model.SuperUser == null"> <!-- It should be enabled only id SuperUser is selected -->
<NoItemsTemplate>
<MudList Clickable = "false">
<MudListItem>
@Localizer["NoItemsWasFound"]
</MudListItem>
</MudList>
</NoItemsTemplate>
<BeforeItemsTemplate>
<MudText Color = "Color.Primary" Class = "mud-list-item mud-list-item-gutters mud-list-item-clickable mud-ripple">@Localizer["PleaseSelectAdminUser"]</MudText>
</BeforeItemsTemplate>
<ProgressIndicatorInPopoverTemplate>
<MudList Clickable = "false">
<MudListItem>
@Localizer["Loading"]
</MudListItem>
</MudList>
</ProgressIndicatorInPopoverTemplate>
</MudAutocomplete>
<ValidationMessage For = "@(() => Model.AdminUserId)" />
</div>
@code {
[Parameter][EditorRequired] public MyModel Model { get; set; } = null!;
private async Task<IEnumerable<UserDTO>> SearchAdminUser(string value)
{
if (Model.SuperUserId.HasValue && Model.SuperUserId.Value > 0)
{
var filter = new { Model.SuperUserId, value };
var result = await _myService.GetAdminUserBySuperUserFiltered(filter);
if (result != null)
{
return result;
}
}
return new List<UserDTO>();
}
private void OnAdminUserCleared(MouseEventArgs args)
{
Model.AdminUser = null;
Model.AdminUserId = null;
StateHasChanged();
}
private void OnAdminUserValueChanged(UserDTO value)
{
Model.AdminUser = value;
Model.AdminUserId = value.Id;
StateHasChanged();
}
}
Несмотря на правильное обновление Model.SuperUser в Child1 и вызов StateHasChanged(), условие Disabled = "Model.SuperUser == null" в Child2 не включает ввод, как ожидалось.
Есть какие-нибудь предложения о том, как правильно включить/отключить ввод в Child2 в зависимости от состояния Model.SuperUser из Child1?





Вы можете использовать каскадные значения для передачи Model из Parent в Childred элементы. Затем используйте обратный вызов события в Children, чтобы передать изменения обратно в Parent.
Вот модифицированная версия предоставленного вами кода.
Вам необходимо использовать объект службы с ограниченной областью или объект каскадного состояния, который использует события для уведомления об изменениях. См. — stackoverflow.com/questions/77687611/…