Обмен данными между Page и NavMenu в Blazor - PullRequest
2 голосов
/ 29 марта 2020

У меня есть стандартный проект Blazor, который имеет следующие компоненты:

-> MainLayout.razor
-> NavMenu.razor
-> Pages/Index.razor
-> Pages/Sub1.razor

MainLayout выглядит следующим образом:

<div class="sidebar">
    <NavMenu />
</div>
<div>@Body</div>

Теперь я хочу обмениваться данными между моими страницами (index.razor, sub1.razor) и navmenu, чтобы я мог добавить что-то подобное в navmenu:

<div><p>You are now on Page: @CurrentPageName</p></div>

Как я могу установить (navMenu) .CurrentPageName непосредственно на моей странице? Я ожидаю, что использование класса stati c для этого не очень хороший вариант.

Ответы [ 3 ]

1 голос
/ 31 марта 2020

Лучшая реализация сервиса с ограниченным доступом:

 public class CurrentPage
    {
        public string CurrentPageName { get; private set; }

        public void SetCurrentPageName(string name)
        {
            if (!string.Equals(CurrentPageName, name)) 
            {
                CurrentPageName = name;
                NotifyStateChanged();
            }
        }

        public event Action OnChange; // event raised when changed

        private void NotifyStateChanged() => OnChange?.Invoke();
    }

Мы не передаем словари объектов, у нас есть простой сервис, который выполняет одну задачу. Единственный способ изменить страницу - позвонить по номеру SetCurrentPageName, который вызывает событие, чтобы потребители знали об измененном имени. Это требуется между не вложенными компонентами, так как в противном случае обновления не распространяются по всему

Нам также необходимо зарегистрировать службу (в том виде, в каком она существует, поскольку текущая страница определяется сессией c) при запуске:

            services.AddScoped<CurrentPage>();

Мы добавим Index.razor и используем это:

@page "/"
@inject CurrentPage currentPage

<h1>Hello, world!</h1>

Welcome to your new app.
<button @onclick="ChangeName">Set Page Name</button>

<SurveyPrompt Title="How is Blazor working for you?" />
@code
{

    protected override void OnInitialized()
    {
        currentPage.SetCurrentPageName("The Home Page");
        base.OnInitialized();
    }

    void ChangeName() => currentPage.SetCurrentPageName("Name changed");
}

и, наконец, на вершине NavMenu.razor:

@inject CurrentPage currentPage

и далее вниз.


    <p>The current page is @currentPage.CurrentPageName</p>

@code {
    protected override void OnInitialized()
    {
        // if the OnChange event is raised, refresh this view
        currentPage.OnChange += () => StateHasChanged();

        base.OnInitialized();
    }

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

[EDIT] Я решил, что шаблон ввода / переопределения для установки имени страницы довольно unBlazor, поэтому я также написал компонент для упростите это - PageName.razor:

@inject CurrentPage currentPage;

@code {
    [Parameter]
    public string Name { get; set; }

    protected override void OnParametersSet()
    {
        currentPage.SetCurrentPageName(Name);
    }
}

Теперь любая страница, желающая установить заголовок, может сделать это:

@page "/fetchdata"
@inject HttpClient Http
<PageName Name="Weather forecast page!" />

Весь потребитель теперь является компонентом:)

1 голос
/ 29 марта 2020

Существует три основных способа связи между компонентами в Blazor. Крис Сэйнти (Chris Sainty) написал хорошую статью, в которой излагается следующее: https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/

В этом сценарии, вероятно, наилучшим вариантом являются каскадное значение или контейнер состояния. Для каскадного значения потребуется, чтобы компонент верхнего уровня содержал это значение, например что-то, что инкапсулирует как <NavMenu>, так и @Body:

@inherits LayoutComponentBase
<MenuState>
<div class="sidebar">
    <NavMenu />
</div>

<div class="main">
    <div class="top-row px-4">
        <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
    </div>

    <div class="content px-4">
        @Body
    </div>
</div>
</MenuState>

. Другой подход заключается в использовании инъецируемой службы, которая обеспечивает Служба состояний, которую вы вводите как в <NavMenu>, так и в компоненты страницы.

0 голосов
/ 31 марта 2020

Используйте сервис Scoped для обмена данными / объектами

В Startup.cs

вы можете добавить свой собственный сервис Scoped:

public void ConfigureServices(IServiceCollection services)
{
   ......
   services.AddScoped<MyScopeService>();
}
public class MyScopeService : Dictionary<string,object>
{
} 

и в NavMenu.razor

@inject MyScopeService mss

@code{
    string _title;
    public void UpdateTitle(string title)
    {
        _title = title;
        StateHasChanged();
    }
}

@{
    mss["NavMenu"] = this;
}
<div>@_title</div>

На целевой странице:


@inject MyScopeService mss
@code{
    void SetTitle()
    {
        NavMenu menu = (NavMenu)mss["NavMenu"];
        menu.UpdateTitle("Hello this is page 1");
    }
}

<button @onclick="SetTitle">SetTitle</button>

...