Как динамически переключать дочерний контент на страницах Blazor - PullRequest
0 голосов
/ 02 октября 2019

Будучи абсолютным новичком, когда дело доходит до веб-разработки, я начал изучать Blazor и узнал, как его использовать, чтобы легко приступить к веб-разработке и теперь борюсь с проблемой.

Я создал страницу Master / Detail, и на этой странице используется главный компонент (список сотрудников) и 2 различных компонента детализации (подробный просмотр сотрудника только для чтения и просмотр редактирования сотрудника).

На главной странице сведений используется следующеемаршруты:

  • https://localhost:44344/masterdetail
  • https://localhost:44344/masterdetail/{id:int}
  • https://localhost:44344/masterdetail/{id:int}/edit

Я пытался достичь этих целей:

  1. Когда пользователь щелкает элемент списка в главном компоненте, он должен отображаться в URL-адресе, например https://localhost:44344/masterdetail/2, и затем загружать подробный вид сотрудника только для чтения в область сведений

    * 1024. *
  2. Когда пользователь нажимает кнопку редактирования, расположенную в подробном представлении сотрудника, доступном только для чтения, главная страница сведений должна переключиться в представление редактирования сотрудника в области сведений и отобразить его в URL-адресе, например https://localhost:44344/masterdetail/2/edit

  3. Когда пользователь нажимает кнопку сохранения, расположенную в представлении редактирования сотрудника, главная страница сведений должна переключаться на представление сведений только для сотрудников в области сведений и отображаться в 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 цели.

Вот упрощенный пример, демонстрирующий проблему:

  1. Создание нового проекта "Приложение Blazor" в Visual Studio
  2. Выбор "Blazor Server App "
  3. Добавьте новый файл .razor и вставьте фрагмент кода в
  4. Посмотрите комментарии и код
  5. Перейдите к 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)

Какова лучшая практика / рекомендация о том, как переключать дочерний контент на странице блейзора?

...