Это код, который работает нормально уже несколько месяцев. Без изменений. И все страницы, кроме первой, открываются нормально. Но эта страница, на которой есть:
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
// commented out to remove that as a cause
// IsLoading = true;
await Task.Delay(1);
// ...
Цель IsLoading
— сделать видимым счетчик загрузки. У меня один и тот же набор кода для большинства моих страниц - на остальных работает.
Task.Delay(1)
никогда не возвращается. Если я закомментирую это, то первое ожидание вызова БД (через EF) не вернется.
Если я не назову await base.OnInitializedAsync()
, то Task.Delay(1)
мгновенно вернется. Это ComponentBase.OnInitializedAsync()
.
Что может вызвать это? Я не понимаю, как может быть тупик, поскольку это первое ожидание внутри OnInitializedAsync
, и поэтому нет ничего, что могло бы также ждать.
Обновлять:
Спиннер находится на бритве этой страницы как:
<ExLoading Visible = "@IsLoading" />
И этот компонент:
<DxLoadingPanel Visible = "@Visible"
PositionTarget = "body"
IsContentBlocked = "true"
ApplyBackgroundShading = "true" />
<DxLoadingPanel>
— это компонент DevExpress.
@MayurEkbote Хорошее предложение. Я прокомментировал IsLoading, так что это не проблема. Все еще есть проблема. Спасибо
Если вы закомментируете IsLoading, не будет ли отображена та часть, которая не готова к рендерингу?
@MayurEkbote Нет, поскольку IsLoading является ложным. В файле Razor может быть что-то (на странице масса компонентов), но как это может остановить вызов Task.Delay()? А если я пропущу этот вызов, то заблокирую первый EntityFramework? Если этот код выполняется, я не понимаю, как вызов в нем, не имеющий никакого отношения к странице бритвы, может зайти в тупик при ожидании.
Существует два способа использования флагов загрузки. Один — if (IsLoading){<progress>}else{<content>}, другой — if (IsLoading){<overlay-progress-high-z-index>}<content>. Если в логике рендеринга <content> возникает тупик, исключение никогда не будет выброшено на стороне рендеринга, и ваш указатель отладки навсегда застрянет в части кода. Это единственное, о чем я могу думать без реального кода.
@MayurEkbote Я добавил компонент бритвы (не повредит). Но вот фундаментальный вопрос: не должно ли быть невозможно, чтобы вызов await Task.Delay(1)
зашел в тупик? По определению код, вызвавший его, не заблокирован, поэтому выполнение этого вызова должно быть свободным.
Вы предполагаете, что в Task.Delay(1) возникла взаимоблокировка. Я предполагаю, что тупик происходит в делегате RenderFragment, который отображает компонент. При асинхронной инициализации компонент полностью визуализируется перед ожиданием, а затем повторно визуализируется после возврата ожидания. Я подозреваю, что во время первого рендеринга до вызова ожидания происходит тупик. Следовательно, Task.Delay(1) никогда не возвращается.
Кстати, поскольку вы используете компонент DevExp, похоже, что он использует JSInterop для рендеринга компонента (PositionTarget = "body" подразумевает это) в Blazor невозможно сделать это изначально). Если JSInterop вызывает проблему, она никогда не отобразится в приложении. Проверьте консоль браузера, если есть проблема.
h/t @MayurEkbote, поскольку они отправили меня удалить компоненты со страницы, чтобы выяснить, был ли это один из них. Это было.
Я имел:
<DxComboBox Data = "@EditModel.AllowedWorkplaces"
ReadOnly = "@(ModeState == Mode.Read)"
InputId = "workplace"
TextFieldName = "@nameof(EventPageModelBase.WorkplaceItem.Text)"
name = "@nameof(EventPageEditModel.Workplace)"
autocomplete = "off"
SelectedItemChanged = "@((EventPageModelBase.WorkplaceItem workplace) => OnWorkplaceClick(workplace))"
@bind-Value = "@EditModel.Workplace">Workplace</DxComboBox>
и проблема заключалась в том, что EditModel.AllowedWorkplaces
был массивом значений перечисления, а EditModel.Workplace
было выбранным перечислением. Я изменил его, чтобы создать класс, который обертывает перечисление и чтобы поле со списком использовало этот класс. И теперь это работает.
Ошибка возникает только в том случае, если указан SelectedItemChanged
. Если это не указано, оно отлично работает с перечислением.
Понятия не имею почему. Читая документацию для DxComboBox
, она никогда не упоминает коллекцию перечислений. Так что это может больше не поддерживаться.
ps. Вместе с изменением был добавлен атрибут TextFieldName
. Изначально у него не было этого атрибута. Но это единственное изменение в коде бритвы.
Спасибо за ч/т. Это одна из причин, по которой я избегаю использования готовых сторонних библиотек для Blazor. Большинство из них непрозрачны, некоторые представляют собой плохую оболочку существующих JS-библиотек, и все они имеют плохую документацию по API. Я использую их только для очень сложных компонентов, таких как диаграммы или особые случаи. В противном случае, по моему опыту, использование простых компонентов + CSS + привязка данных удовлетворяет все потребности.
Можете ли вы поделиться частью бритвы, которая отображается, когда IsLoading имеет значение true?