#c# #html #blazor
#c# #HTML #blazor
Вопрос:
Вижу какое-то странное поведение в приложении Blazor (сервер), над которым я работаю. Новичок в этой технологии и не настолько хорош в веб-разработке для начала, но вот я сижу.
Проблема в том, что по какой-то причине, и из-за отсутствия кода, который я намеренно запускаю, Blazor удаляет / добавляет HTML-элементы на мою страницу без обратного вызова кода C # сервера, насколько я могу судить. Это делается только для 1 из 3 элементов выбора html, которые кодируются точно так же на странице. Этот конкретный элемент select, похоже, запускает логику фильтрации, которая у меня есть в C #, но, хоть убейте, я не могу понять, как он это делает. И даже если это так, это не совсем правильно в том, что он делает, поскольку он относится к моей логике C #.
Удаляются кнопки span /, отображаемые в @foreach, показанном ниже, но ТОЛЬКО при нажатии на что-либо в элементе выбора «Коды состояния». Это происходит только после первой фильтрации, которая отображает содержимое в @foreach в первый раз. После этого изменение выбора ‘Status Code’ начинает изменять клиентскую часть HTML, но только для этого одного элемента select. Не два других. Обратите внимание, что в настоящее время у меня есть applyFilter, закомментированный в C #, он срабатывает только при нажатии кнопки «Поиск». Остальные 2 элемента select ведут себя точно так, как ожидалось, то есть с @foreach ничего не происходит, пока я физически не нажму кнопку «Поиск».
Я установил точку останова для изменения поддерева в инструментах разработчика браузера для этого блока @foreach, и я описываю, что происходит в этом событии и достигается точка останова. 1-й и 3-й элементы выбора никогда не приводят к изменению поддерева, 2-й делает. Разрыв изменения поддерева указывает на то, что blazor.server.js вызывает ‘removeChildElement’.
В настоящее время у меня нет клиентской части javascript, кроме того, что может делать blazor. Итак, это чистая серверная часть Blazor, HTML / C # с битами сценариев Razor-иш для рендеринга страницы.
Заранее спасибо за любые мысли о том, как отладить это дальше, или выяснить, что я здесь сделал не так … чего может быть МНОГО в том, как я написал это приложение.
<ul class="nav flex-column">
<li class="nav-item px-3">
<select class="form-control" @onchange="OnChangeFilterSite">
<option value="all" selected>Select Site :</option>
@foreach (string item in RtuServiceData.Sites) {
if (filterSite != null amp;amp; filterSite == @item) {
<option selected value="@item">@item</option>
}
else {
<option value="@item">@item</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @onchange="OnChangeFilterStatusCode">
<option value="all" selected>RTU Status :</option>
@foreach (AcceptedStatus item in RtuServiceData.StatusCodes) {
if (filterStatusCode != null amp;amp; filterStatusCode == item.Code) {
<option selected value="@item.Code">@item.Description</option>
}
else {
<option value="@item.Code">@item.Description</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @onchange="OnChangeFilterMatchingOption">
<option value="all" selected>Matching Option :</option>
@foreach (string item in RtuServiceData.MatchingOptions) {
if (filterMatchingOption != null amp;amp; filterMatchingOption == @item) {
<option selected value="@item">@item</option>
}
else {
<option value="@item">@item</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<label class="text-white"><b>Filter :</b></label>
<input type="text" class="form-control" @onchange="OnChangeFilterName"/>
<br>
<button class="btn btn-dark" @onclick="@(e => _ApplyFilter())">Search</button>
<br><br>
</li>
<li class="nav-item px-3">
<div style="height: 300px; overflow: auto; padding-right: 15px">
@foreach (RtuComposite item in RtuServiceData.RTUs_Filtered) {
<span class="btn btn-block @item.ACCEPTED_STATUS_BUTTON_CLASS" @onclick="@(e => _SetRtu(@item.Proposed.ID))">@item.Proposed.RTU</span>
}
</div>
</li>
</ul>
И вот код C #, который обрабатывает различные события @onchange.
private string filterSite;
public void OnChangeFilterSite(ChangeEventArgs e)
{
filterSite = e.Value.ToString();
//_ApplyFilter();
}
private string filterStatusCode;
public void OnChangeFilterStatusCode(ChangeEventArgs e)
{
filterStatusCode = e.Value.ToString();
//_ApplyFilter();
}
private string filterMatchingOption;
public void OnChangeFilterMatchingOption(ChangeEventArgs e)
{
filterMatchingOption = e.Value.ToString();
//_ApplyFilter();
}
private string filterName;
public void OnChangeFilterName(ChangeEventArgs e)
{
filterName = e.Value.ToString();
//_ApplyFilter();
}
Комментарии:
1. Вы пробовали ставить точку останова в коде C # в Visual Studio и проверять, выполняется ли код так, как вы ожидаете? Вы можете установить точку останова для всех своих методов и посмотреть, что происходит.
2. ДА. При нажатии / выборе одного из элементов (в последнем коде, который я опубликовал ниже) в элементах выбора не выполняется код C #. И до этого последнего изменения единственным выполнявшимся кодом была установка резервной частной переменной для соответствующего элемента select . Вы должны нажать кнопку «Поиск», чтобы вызвать C # для выполнения каких-либо действий. Я не уверен, как описать, что происходит, но похоже, что в какой-то момент он каким-то образом создал некоторый javascript и запустил фильтрацию на стороне клиента для этого 1 отдельного элемента select. Как я уже сказал, остальные 2 ведут себя иначе. Не имеет НИКАКОГО смысла.
Ответ №1:
Хорошей идеей будет привязать @key=»что-то уникальное» к компонентам и элементам в циклах. Это помогает Blazor узнать, что изменилось. Поместите его в диапазон, поскольку он находится в цикле
Комментарии:
1. Спасибо, добавил это с уникальным значением w /в пределах этого <li> <div> .
Ответ №2:
Спасибо. Просто прокомментировал сайт и соответствующие выборки, такое же поведение. Первый выбор кода состояния и переход между опциями ничего не дает. Нажатие кнопки «Поиск» фильтрует, как и ожидалось, затем при первом нажатии кнопки «Поиск». Затем, если я переключусь обратно на элемент «все» в списке кодов состояния, все кнопки исчезнут. Нажатие на дополнительные параметры фильтрует правильно. Это так странно.
Пересмотренный код ниже…
<ul class="nav flex-column">
<li class="nav-item px-3">
<select class="form-control" @bind="@filterSite">
<option value="all" selected>Select Site :</option>
@foreach (string item in RtuServiceData.Sites) {
if (filterSite != null amp;amp; filterSite == @item) {
<option @key="@item" selected value="@item">@item</option>
}
else {
<option @key="@item" value="@item">@item</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @bind="@filterStatusCode">
<option value="all" selected>RTU Status :</option>
@foreach (AcceptedStatus item in RtuServiceData.StatusCodes) {
if (filterStatusCode != null amp;amp; filterStatusCode == item.Code) {
<option @key="@item.Code" selected value="@item.Code">@item.Description</option>
}
else {
<option @key="@item.Code" value="@item.Code">@item.Description</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @bind="@filterMatchingOption">
<option value="all" selected>Matching Option :</option>
@foreach (string item in RtuServiceData.MatchingOptions) {
if (filterMatchingOption != null amp;amp; filterMatchingOption == @item) {
<option @key="@item" selected value="@item">@item</option>
}
else {
<option @key="@item" value="@item">@item</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<label class="text-white"><b>Filter :</b></label>
<input type="text" class="form-control" @bind="@filterName"/>
<br>
<button class="btn btn-dark" @onclick="@(e => _ApplyFilter())">Search</button>
<br><br>
</li>
<li class="nav-item px-3">
<div style="height: 300px; overflow: auto; padding-right: 15px">
@foreach (RtuComposite item in RtuServiceData.RTUs_Filtered) {
<span @key="@item.Proposed.ID" class="btn btn-block @item.ACCEPTED_STATUS_BUTTON_CLASS" @onclick="@(e => _SetRtu(@item.Proposed.ID))">@item.Proposed.RTU</span>
}
</div>
</li>
</ul>
private string filterSite;
@* public void OnChangeFilterSite(ChangeEventArgs e)
{
filterSite = e.Value.ToString();
//_ApplyFilter();
} *@
private string filterStatusCode;
@* public void OnChangeFilterStatusCode(ChangeEventArgs e)
{
filterStatusCode = e.Value.ToString();
//_ApplyFilter();
} *@
private string filterMatchingOption;
@* public void OnChangeFilterMatchingOption(ChangeEventArgs e)
{
filterMatchingOption = e.Value.ToString();
//_ApplyFilter();
} *@
private string filterName;
@* public void OnChangeFilterName(ChangeEventArgs e)
{
filterName = e.Value.ToString();
//_ApplyFilter();
} *@
Комментарии:
1. «все кнопки исчезают» Какие кнопки? Вы имеете в виду элементы в элементе select ? Пожалуйста, обновите свой ответ кодом для метода _ApplyFilter .
2. Кнопки — это те, которые отображаются в самом последнем LI / DIV в нижней части HTML. Порядок событий здесь. Страница загружается, кнопки заполнены, нажмите пункт 1 в коде состояния выберите. Нажмите «Поиск». Код C # запускает _ApplyFilter . Список кнопок фильтруется. Нажмите назад к элементу «все» по умолчанию в коде состояния, кнопки исчезнут (ничего не должно произойти). Они удаляются по одному за раз, на стороне клиента, код C # не запускается.
Ответ №3:
Извините, под «кнопкой» я имел в виду DIV в самом низу HTML, который содержит элементы SPAN, использующие класс bootstrap btn для стилизации. Полный код для боковой панели приложения.
<div>
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="rtu">
<span class="oi oi-home" aria-hidden="true"></span> RTU
@* amp;nbspamp;nbsp<span class="spinner-border" role="status"></span> *@
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="analogs">
<span class="oi oi-list-rich" aria-hidden="true"></span> Analogs
@* amp;nbspamp;nbsp<span class="spinner-border" role="status"></span> *@
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="digitals">
<span class="oi oi-list-rich" aria-hidden="true"></span> Digitals
@* amp;nbspamp;nbsp<span class="spinner-border" role="status"></span> *@
</NavLink>
</li>
</ul>
<br>
<ul class="nav flex-column">
<li class="nav-item px-3">
<select class="form-control" @bind="@filterSite">
<option value="all" selected>Select Site :</option>
@foreach (string item in RtuServiceData.Sites) {
if (filterSite != null amp;amp; filterSite == @item) {
<option @key="@item" selected value="@item">@item</option>
}
else {
<option @key="@item" value="@item">@item</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @bind="@filterStatusCode">
<option value="all" selected>RTU Status :</option>
@foreach (AcceptedStatus item in RtuServiceData.StatusCodes) {
if (filterStatusCode != null amp;amp; filterStatusCode == item.Code) {
<option @key="@item.Code" selected value="@item.Code">@item.Description</option>
}
else {
<option @key="@item.Code" value="@item.Code">@item.Description</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<select class="form-control" @bind="@filterMatchingOption">
<option value="all" selected>Matching Option :</option>
@foreach (string item in RtuServiceData.MatchingOptions) {
if (filterMatchingOption != null amp;amp; filterMatchingOption == @item) {
<option @key="@item" selected value="@item">@item</option>
}
else {
<option @key="@item" value="@item">@item</option>
}
}
</select>
</li>
<li class="nav-item px-3">
<label class="text-white"><b>Filter :</b></label>
<input type="text" class="form-control" @bind="@filterName"/>
<br>
<button class="btn btn-dark" @onclick="@(e => _ApplyFilter())">Search</button>
<br><br>
</li>
<li class="nav-item px-3">
<div style="height: 300px; overflow: auto; padding-right: 15px">
@foreach (RtuComposite item in RtuServiceData.RTUs_Filtered) {
<span @key="@item.Proposed.ID" class="btn btn-block @item.ACCEPTED_STATUS_BUTTON_CLASS" @onclick="@(e => _SetRtu(@item.Proposed.ID))">@item.Proposed.RTU</span>
}
</div>
</li>
</ul>
@code {
private string filterSite;
@* public void OnChangeFilterSite(ChangeEventArgs e)
{
filterSite = e.Value.ToString();
//_ApplyFilter();
} *@
private string filterStatusCode;
@* public void OnChangeFilterStatusCode(ChangeEventArgs e)
{
filterStatusCode = e.Value.ToString();
//_ApplyFilter();
} *@
private string filterMatchingOption;
@* public void OnChangeFilterMatchingOption(ChangeEventArgs e)
{
filterMatchingOption = e.Value.ToString();
//_ApplyFilter();
} *@
private string filterName;
@* public void OnChangeFilterName(ChangeEventArgs e)
{
filterName = e.Value.ToString();
//_ApplyFilter();
} *@
protected override async Task OnInitializedAsync()
{
await Task.Run(_Load);
}
protected void _Load() {
RtuServiceData.RTUs = RtuService._GetRtuList();
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs;
}
private void _ApplyFilter() {
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs; //get the full list from the singleton
//only filter on site when it's one of the values in the list
if (!string.IsNullOrEmpty(filterSite) amp;amp; RtuServiceData.Sites.Contains(filterSite)) {
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.SITE == filterSite).ToList();
}
//only filter on status code when it's one of the values in the list
if (!string.IsNullOrEmpty(filterStatusCode) amp;amp; RtuServiceData.StatusCodes.Select(x => x.Code).Contains(filterStatusCode)) {
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Accepted.ACCEPTED_STATUS == filterStatusCode);
}
//only filter on matching option when it's one of the values in the list
switch (filterMatchingOption) {
case "100% Match":
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.MATCH_PERCENT == 100);
break;
case "< 100% Match":
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.MATCH_PERCENT > 0 amp;amp; r.Proposed.MATCH_PERCENT < 100);
break;
case "No Match":
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.MATCH_PERCENT == 0);
break;
default: // default: provides the same functionality as checking filterSite and filterStatusCode against legit values above
break;
}
//only filter on name when it's populated
if (!string.IsNullOrEmpty(filterName)) {
RtuServiceData.RTUs_Filtered = RtuServiceData.RTUs_Filtered.Where(r => r.Proposed.RTU.ToUpper().StartsWith(filterName.ToUpper()));
}
}
private void _SetRtu(int id) {
RtuServiceData.SelectedRtu = null;
NavigationManager.NavigateTo("/");
RtuServiceData.SelectedRtu = RtuService._GetRtu(id);
NavigationManager.NavigateTo("rtu");
}
}