Я работаю с моделью представления, содержащей коллекции, отображаемые в MudTables. Мне нужно редактировать сложные элементы в этих таблицах и реализовать функцию поиска с помощью MudAutocomplete.
Вот в чем проблема: я привязал элемент контекста таблицы к значению автозаполнения. Однако когда я ищу элемент, исходное значение не меняется. Я также не могу очистить автозаполнение, и проверка не запускается.
Я ожидаю, что смогу изменить значение во входных данных автозаполнения и изменить элемент контекста в связанных элементах таблицы.
в качестве примера у нас есть эта попытка https://try.mudblazor.com/snippet/cuQyaKkyqKQQUoGG
Вот упрощенная версия моего кода:
<MudGrid>
<MudItem xs = "12">
<MudCard Elevation = "0">
<MudCardContent>
<MudForm @ref = "_form" Model = "@_selectedTeam" Validation = "@(_selectedTeamValidator.ValidateValue)" ValidationDelay = "0" IsValid = "@(_selectedTeamValidator.Validate(_selectedTeam).IsValid)">
<MudStack>
<MudText Typo = "Typo.h4" Style = "text-transform: uppercase">S&P Team</MudText>
<MudTable Items = "@_selectedTeam.TeamMembers" Dense = "true" CanCancelEdit = "true" HorizontalScrollbar = "true" Breakpoint = "Breakpoint.None">
<HeaderContent>
<MudTh>Role</MudTh>
<MudTh>Name</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel = "Role">@context.Role</MudTd>
<MudTd DataLabel = "Name">@context.DisplayName</MudTd>
</RowTemplate>
<RowEditingTemplate>
<MudTd DataLabel = "Role">@context.Role</MudTd>
<MudTd DataLabel = "Name">
@if (context.Role == "ResponsibleAdvisor")
{
<MudAutocomplete T = "SalesProcessParty"
@bind-Value = "@context"
@ref = "_responsibleAdvisorAutocomplete"
Validation=@(async () => await _teamMemberValidator.ValidatePropertyValueAsync(context, "PartyId"))
For = "@(() => context)"
ToStringFunc = "@(x => x?.DisplayName)"
SearchFunc = "GetEmployees"
Variant = "Variant.Outlined"
Margin = "Margin.Dense" />
}
@if (context.Role == "SupportingAdvisor")
{
<MudAutocomplete T = "SalesProcessParty"
@bind-Value = "@context"
@ref = "_supportingAdvisorAutocomplete"
For = "@(() => context)"
Immediate = "false"
Clearable = "true"
ResetValueOnEmptyText = "true"
ToStringFunc = "@(x => x.DisplayName)"
SearchFunc = "GetEmployees"
Variant = "Variant.Outlined"
Margin = "Margin.Dense" />
}
</MudTd>
</RowEditingTemplate>
</MudTable>
</MudStack>
</MudForm>
</MudCardContent>
</MudCard>
</MudItem>
</MudGrid>
@code {
private bool _processing;
private TeamMemberValidator _teamMemberValidator = new();
private CustomerMemberValidator _customerMemberValidator = new();
private CustomerTeamValidator _selectedTeamValidator = new();
private CustomerTeamViewModel _selectedTeam = new();
private MudForm _form;
protected override void OnInitialized()
{
_selectedTeam = new()
{
TeamMembers = new List<SalesProcessParty>()
{
new(){
PartyId = Guid.NewGuid(),
FirstName = "Lead",
LastName = "Leader",
Role = "ResponsibleAdvisor"
},
new(){
PartyId = Guid.NewGuid(),
FirstName = "Support",
LastName = "Supporter",
Role = "SupportingAdvisor"
}
},
CustomerMembers = new List<SalesProcessParty>()
{
new(){
PartyId = Guid.NewGuid(),
FirstName = "Customer",
LastName = "Contact",
Role = "CustomerContact"
}
}
};
base.OnInitialized();
}
private async Task<IEnumerable<SalesProcessParty>> GetEmployees(string searchText)
{
if (string.IsNullOrEmpty(searchText) || string.IsNullOrWhiteSpace(searchText))
return new List<SalesProcessParty>();
await Task.Delay(2000);
var persons = parties.Where(x => !_selectedTeam.TeamMembers.Select(y => y.PartyId).Contains(x.PartyId) && x.DisplayName.Contains(searchText)) ?? new List<SalesProcessParty>();
return persons;
}
private IList<SalesProcessParty> parties = new List<SalesProcessParty>()
{
new()
{
PartyId = Guid.NewGuid(),
FirstName = "Person",
LastName = "One",
},
new()
{
PartyId = Guid.NewGuid(),
FirstName = "Person",
LastName = "Two",
},
new()
{
PartyId = Guid.NewGuid(),
FirstName = "Person",
LastName = "Three",
},
new()
{
PartyId = Guid.NewGuid(),
FirstName = "Person",
LastName = "Four",
},
new()
{
PartyId = Guid.NewGuid(),
FirstName = "Person",
LastName = "Five",
}
};
}

Добро пожаловать в MudBlazor, есть ряд проблем, но давайте начнем с очевидной.
Вы не можете двусторонне или написать привязать значение ячейки в строке к @context самой строки.
Ваш MudAutocomplete находится внутри строки, поэтому ваша привязка может влиять только на свойства этой строки, вы не можете волшебным образом изменить саму строку. Подумайте об этом: если привязка сработала и ваш выбор не привел к выделению объекта, то сама строка должна перестать существовать...
Думайте о строке как о контейнере: MudAutocomplete в ячейке этого контейнера может изменить только значение в контейнере, но не может изменить сам контейнер.
Также неочевидно, какой смысл создавать несколько ссылок автозаполнения, имеющих одинаковую конфигурацию. Если вы намеревались отфильтровать выборки с помощью context.Role, лучшим решением будет передать это значение в функцию поиска.
Другое наблюдение заключается в том, что вы привязываете ссылки на объекты, а не искомые значения, за исключением того, что ваш список объектов в раскрывающемся списке не имеет соответствующей ссылки на значения в TeamMembers
Автозаполнение в MudBlazor ничем не отличается от полей со списком или раскрывающихся списков в других платформах, применяются стандартные правила взаимодействия. Вы можете использовать их для выбора примитивного или статического значения из существующего списка, который можно скопировать по значению, но для правильной визуализации список должен содержать значение, соответствующее исходному значению привязанной модели. Связанное свойство или функция должна иметь возможность получать тип элемента, выбранного для закрепления значения.
Структура вашей модели представления просто не соответствует пользовательскому интерфейсу. При использовании такой модели представления в сетке чаще всего присутствуют действия «Добавить новую запись» или «Удалить существующие», если SalesProcessParty необходимо сопоставить с существующей записью, в этом случае MudAutocomplete будет находиться за пределами сетки и являться ее частью. шаблона или формы добавления записи.
В качестве альтернативы модель представления будет иметь список записей-указателей, то есть не SalesProcessParty, а связывающий объект с PartyId, тогда вы все равно можете добавлять и удалять записи, но теперь мы можем привязать MudAutocomplete к свойству PartyId, а не ко всей строке @context. .
Ни один из этих вариантов не соответствует пользовательскому интерфейсу, который вы закодировали, что наводит на мысль, что
TeamMembersвообще не должно быть списком.
Еще один вариант — сделать свойства ResponsibleAdvisor и SupportingAdvisor элемента CustomerTeamViewModel, а не элементов вообще в списке. В этом случае может вообще не иметь смысла наследовать SalesProcessParty от Party, вместо этого у него может быть свойство, чтобы мы могли выбрать и назначить Party данному экземпляру SalesProcessParty.
Поскольку здесь имеется большое количество переменных, я не буду пытаться сконструировать закодированный ответ, однако это все равно оказалось ценным мыслительным упражнением. В сообщении вам необходимо четко указать, каково окончательное намерение, в настоящий момент я сталкиваюсь с выбором: либо изменить пользовательский интерфейс, чтобы он соответствовал намерению ViewModel, либо изменить ViewModel, чтобы он соответствовал намерению пользовательского интерфейса.
Уважайте бритву Оккама. В данном случае думайте об этом как о бритве Оккама: если это слишком сложно, то вы, вероятно, делаете это неправильно.