Blazor - страница бритвы не обновляется после изменения свойства из DI Service - PullRequest
2 голосов
/ 06 ноября 2019

Использование dotnet 3.1.100-preview2-014569

Хорошо, рассмотрите следующий пример:

Создайте новый проект Blazor WebAssemply из шаблона, затем добавьте следующее:

books.razor

@page "/books"
@inject BookService bookService

@if (bookService.isLoaned)
{
    <p><em>Book loaned</em></p>
}
else
{
    <p><em>Book returned</em></p>
}

BookService.cs

public class BookService
    {
        public int BookId { get; set; }

        public string Title { get; set; }

        public bool isLoaned { get; set; }
    }

Startup.cs

public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<BookService>();
        }

NavMenu.razor

@inject BookService bookService;
<div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">BlazorBlank_PV2</a>
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="books" @onclick="LoanBookClicked">
                <span class="oi oi-plus" aria-hidden="true"></span>Loan Book
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="books" @onclick="ReturnBookClicked">
                <span class="oi oi-list-rich" aria-hidden="true"></span>Return Book
            </NavLink>
        </li>
    </ul>
</div>

@code {
    private bool collapseNavMenu = true;

    private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;

    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }

    private void LoanBookClicked()
    {
        bookService.isLoaned = true;       
    }
    private void ReturnBookClicked()
    {
        bookService.isLoaned = false;
    }


}

Что происходит: Not rendering issue

Ожидаемое поведение: при нажатии на пункт меню «Заемная книга» на странице должно отображаться «Заемная книга» или, если я нажимаю «Возврат книги», должно отображаться «Книга возвращена». Но это происходит только в том случае, если я нажимаю на другую страницу, например «Домой», а затем снова на нее.

Как заставить страницу повторно визуализировать / перепроверить обновленные значения из BookService, даже если она уже находится на той же странице?

Спасибо!

Ответы [ 2 ]

3 голосов
/ 06 ноября 2019

books.razor (добавить обработчик для нового события onchange службы книги)

@page "/books"
@inject BookService bookService

@if (bookService.isLoaned)
{
    <p><em>Book loaned</em></p>
}
else
{
    <p><em>Book returned</em></p>
}

@code{
 protected override void OnInitialized()
    {
        bookService.OnChange += StateHasChanged;
    }
}

BookService.cs (добавить действие события, изменить свойство только для чтения, добавить установщик, событие триггераwill NotifyStateChanged ()

public class BookService
    {   
        public event Action OnChange;

        public int BookId { get; set; }

        public string Title { get; set; }

        public bool isLoaned { get; }

        public void SetLoanedState(bool State)
        {
           isLoaned  = State;
           NotifyStateChanged();
        }

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

    }

NavMenu.razor (изменить на использование службы SetLoanedState ()

@inject BookService bookService;
<div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">BlazorBlank_PV2</a>
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="books" @onclick="LoanBookClicked">
                <span class="oi oi-plus" aria-hidden="true"></span>Loan Book
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="books" @onclick="ReturnBookClicked">
                <span class="oi oi-list-rich" aria-hidden="true"></span>Return Book
            </NavLink>
        </li>
    </ul>
</div>

@code {
    private bool collapseNavMenu = true;

    private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;

    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }

    private void LoanBookClicked()
    {
        bookService.SetLoanedState(true);       
    }
    private void ReturnBookClicked()
    {
        bookService.SetLoanedState(false);
    }


}

для получения дополнительной информации см. сообщение в блоге Криса Сэйнти здесь itделает это действительно ясным

1 голос
/ 06 ноября 2019

Вот новое решение, в котором я реализую интерфейс INotifyPropertyChanged в классе BookService. Зачем использовать этот интерфейс?

  • Он также может применяться к другим свойствам

  • Уведомление клиентов об изменении значения свойства является важной частьюхорошие сервисы, и это не ограничивается только вызовом StateHasChanged исключительно для этой цели.

  • С реализованным интерфейсом INotifyPropertyChanged я могу передавать данные о событиях зарегистрированным или подписывающимся объектам.

Важно: Вызов метода для обновления значения свойства, такого как bookService.SetLoanedState(false), является плохим программированием и разработкой анти-шаблонов. Свойство может иметь два метода доступа: get и set, и их следует использовать для получения значения и его изменения. Методы имеют разные роли ...

BookService.cs


using System.ComponentModel;
using System.Runtime.CompilerServices;



public class BookService : INotifyPropertyChanged
    {
        private bool isLoaned;
        public event PropertyChangedEventHandler PropertyChanged;

        public int BookId { get; set; }

        public string Title { get; set; }


        public bool IsLoaned
        {
            get
            {
                return this.isLoaned;
            }

            set
            {
                if (value != this.isLoaned)
                {
                    this.isLoaned = value;
                    NotifyPropertyChanged();
                }
            }
        }


        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

Books.razor

@page "/books"
@inject BookService bookService
@using System.ComponentModel


@if (bookService.IsLoaned)
{
    <p><em>Book loaned</em></p>
}
else
{
    <p><em>Book returned</em></p>
}

@code{

    protected override void OnInitialized()
    {
        bookService.PropertyChanged += PropertyHasChanged;
    }
    private void PropertyHasChanged(object sender, PropertyChangedEventArgs args)
    {
         StateHasChanged();
    }
}

NavMenu.razor

@code {

    // Code removed for brevity

    private void LoanBookClicked()
    {
        bookService.IsLoaned = true;      
    }
    private void ReturnBookClicked()
    {
        bookService.IsLoaned = false;      
    }
}

Надеюсь, это работает ...

...