Будучи абсолютным новичком, когда дело доходит до веб-разработки, я начал изучать Blazor и узнал, как его использовать, чтобы легко приступить к веб-разработке и теперь борюсь с проблемой.
Я создал страницу Master / Detail, и на этой странице используется главный компонент (список сотрудников) и 2 различных компонента детализации (подробный просмотр сотрудника только для чтения и просмотр редактирования сотрудника).
На главной странице сведений используется следующеемаршруты:
https://localhost:44344/masterdetail
https://localhost:44344/masterdetail/{id:int}
https://localhost:44344/masterdetail/{id:int}/edit
Я пытался достичь этих целей:
Когда пользователь щелкает элемент списка в главном компоненте, он должен отображаться в URL-адресе, например https://localhost:44344/masterdetail/2
, и затем загружать подробный вид сотрудника только для чтения в область сведений
* 1024. * Когда пользователь нажимает кнопку редактирования, расположенную в подробном представлении сотрудника, доступном только для чтения, главная страница сведений должна переключиться в представление редактирования сотрудника в области сведений и отобразить его в URL-адресе, например https://localhost:44344/masterdetail/2/edit
Когда пользователь нажимает кнопку сохранения, расположенную в представлении редактирования сотрудника, главная страница сведений должна переключаться на представление сведений только для сотрудников в области сведений и отображаться в URL-адресе как * 1032. *
Проблемы, с которыми я столкнулся: когда пользователь находится в режиме только для чтения и затем нажимает кнопку редактирования, мой код вызывает NavigationManager.NavigateTo($"/masterdetail/{Id}/edit");
, который переключает URL-адрес в адресной строкебраузера, но не вызывает метод жизненного цикла OnParametersSet()
главной страницы сведений. Кажется, Blazor повторно использует экземпляр, если Id [Parameter] не изменил его значение.
То же самое происходит, когда пользователь находится в / masterdetail / {Id} / редактировании маршрута (введенного черезадресная строка браузера) и затем нажимает кнопку сохранения.
Что я узнал при исследовании проблемы:
- Я знаю, что мог бы использовать параметр forceLoad вызова
NavigationManager.NavigateTo($"/masterdetail/{Id}/edit", true);
, например:это, , но это приведет к полному обновлению страницы , и я не уверен, если это необходимо. - Я знаю, что мог бы использовать
EventCallback<T>
в своих дочерних компонентах и реагировать наэти события на родительской главной странице сведений, но это похоже на обходной путь. - Я искал способ " маршрутизации внутри страницы блейзора " и наткнулся на такие темы, как " Области "и" Частичное представление", но похоже, что это концепции MVC.
- Я также обнаружил нечто, называемое" RouteView"(https://github.com/aspnet/AspNetCore/blob/2e4274cb67c049055e321c18cc9e64562da52dcf/src/Components/Components/src/RouteView.cs), который является компонентом Blazor, но мне не повезло, используя его для мy цели.
Вот упрощенный пример, демонстрирующий проблему:
- Создание нового проекта "Приложение Blazor" в Visual Studio
- Выбор "Blazor Server App "
- Добавьте новый файл .razor и вставьте фрагмент кода в
- Посмотрите комментарии и код
- Перейдите к
https://localhost:44344/masterdetail/
и попробуйтесам по себе
@*Default route for this page when no entry is selected in the master list*@
@page "/masterdetail"
@*Route for this page when an entry is selected in the master list. The detail area should show a readonly view / component*@
@page "/masterdetail/{id:int}"
@*Route for this page when an entry is selected in the master list and the user clicked the edit button in the readonly view / component. The detail area should show a edit view / component*@
@page "/masterdetail/{id:int}/edit"
@using Microsoft.AspNetCore.Components
@inject NavigationManager NavigationManager
<h1>MyMasterDetailPage</h1>
<br />
<br />
<br />
<div>
<h1>Master Area</h1>
<ul class="nav flex-column">
<li class="nav-item px-3">
<button @onclick=@(mouseEventArgs => ShowListItemDetails(1))>Item 1</button>
</li>
<li class="nav-item px-3">
<button @onclick=@(mouseEventArgs => ShowListItemDetails(2))>Item 2</button>
</li>
<li class="nav-item px-3">
<button @onclick=@(mouseEventArgs => ShowListItemDetails(3))>Item 3</button>
</li>
</ul>
</div>
<br />
<br />
<br />
<div>
<h1>Detail Area</h1>
@{
if (_isInEditMode)
{
// In the real project a <EmployeeEditComponent></EmployeeEditComponent> is being used here instead of the h2
<h2>Edit view for item no. @Id</h2>
<h3>Imagine lots of editable fields here e.g. TextBoxes, DatePickers and so on...</h3>
<button @onclick=@SaveChanges> save...</button>
}
else
{
// In the real project a <EmployeeDetailComponent></EmployeeDetailComponent> is being used here instead of the h2
<h2>ReadOnly view for item no. @Id</h2>
<h3>Imagine lots of NON editable fields here. Probably only labels...</h3>
<button @onclick=@SwitchToEditMode> edit...</button>
}
}
</div>
@code {
private bool _isInEditMode;
[Parameter]
public int Id { get; set; }
protected override void OnParametersSet()
{
// This lifecycle method is not called if the [Parameter] has already been set as Blazor seems to reuse the instance if the [Parameter] Id has not changed it's value.
// For example this method is not being called when navigating from /masterdetail/1 to /masterdetail/1/edit
Console.WriteLine($"Navigation parameters have been set for URI: {NavigationManager.Uri}");
_isInEditMode = NavigationManager.Uri.EndsWith("edit");
base.OnParametersSet();
}
private void ShowListItemDetails(int id)
{
Console.WriteLine($"Showing readonly details of item no. {id}");
NavigationManager.NavigateTo($"/masterdetail/{id}");
}
private void SwitchToEditMode()
{
Console.WriteLine("Switching to edit mode...");
NavigationManager.NavigateTo($"/masterdetail/{Id}/edit");
// Setting _isInEditMode = true here would work and update the UI correctly.
// In the real project this method is part of the <EmployeeEditComponent></EmployeeEditComponent> and therefore has no access to _isInEditMode as it belongs to the <MyMasterDetailPage> component.
// I know that I could create a public EventCallback<MouseEventArgs> OnClick { get; set; } in the <EmployeeEditComponent> and react to that event here in the <MyMasterDetailPage> component but is that really the right way to do this?
//_isInEditMode = true;
}
private void SaveChanges()
{
Console.WriteLine("Saving changes made in edit mode and switching back to readonly mode...");
NavigationManager.NavigateTo($"/masterdetail/{Id}");
// Setting _isInEditMode = false here would work and update the UI correctly.
// In the real project this method is part of the <EmployeeDetailComponent></EmployeeDetailComponent> and therefore has no access to _isInEditMode as it belongs to the <MyMasterDetailPage> component
// I know that I could create a public EventCallback<MouseEventArgs> OnClick { get; set; } in the <EmployeeDetailComponent> and react to that event here in the <MyMasterDetailPage> component but is that really the right way to do this?
//_isInEditMode = false;
}
}
Мои настройки:
- Visual Studio 2019 16.3.1
- .NET Core 3.0 SDK - установщик Windows x64 (v3. 0.100)
Какова лучшая практика / рекомендация о том, как переключать дочерний контент на странице блейзора?