6

使用 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;
    }


}

怎么了: 不渲染问题

预期行为:单击菜单项 Loan Book 时,页面应显示 Book Loaned,或者如果我单击 Return Book,则应显示 Book Return。但这只有在我单击另一个页面(例如主页)然后再返回时才会发生。

即使页面已经在同一页面上,如何强制页面重新渲染/重新检查来自 BookService 的更新值?

谢谢!

4

2 回答 2

5

这是我在 BookService 类中实现 INotifyPropertyChanged 接口的新解决方案。为什么要使用这个接口?

  • 它也可以应用于其他属性

  • 通知客户属性值已更改是良好服务的重要组成部分,这不仅限于仅为此目的调用 StateHasChanged。

  • 通过实现 INotifyPropertyChanged 接口,我可以将事件数据传递给已注册或订阅的对象。

重要提示:调用方法来更新属性值bookService.SetLoanedState(false)是一种糟糕的编程和反模式设计。一个属性可以有两个访问器,get 和 set,它们应该用于获取值和更改值。方法有不同的作用...

图书服务.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));
            }
        }
    }

书籍.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();
    }
}

导航菜单.razor

@code {

    // Code removed for brevity

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

希望这有效...

于 2019-11-06T10:54:26.587 回答
4

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(添加事件动作,将属性改为只读,添加setter,触发事件会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);
    }


}

欲了解更多信息,请查看 Chris Sainty 的博客文章,很清楚

于 2019-11-06T10:24:27.880 回答