Blazor - razor page not updating after property from DI Service is changed

前端 未结 2 1407
刺人心
刺人心 2021-01-05 20:28

Using dotnet 3.1.100-preview2-014569

Ok consider the following example:

Create a new Blazor WebAssemply project from template, then add the following:

<
相关标签:
2条回答
  • 2021-01-05 20:40

    books.razor (add a handler for the new onchange event of the book service )

    @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 (add an event action,change the property to readonly, add a setter, trigger event 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 (change to use service 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);
        }
    
    
    }
    

    for more information look at Chris Sainty's blog post here it makes this really clear

    0 讨论(0)
  • 2021-01-05 20:44

    Here's a new solution in which I implement the INotifyPropertyChanged intereface in the BookService class. Why use this interface ?

    • It can be applied to other properties as well

    • Notifying clients that a property value has changed is essential part of good services, and this is not limited to only call the StateHasChanged solely for this purpose.

    • With the INotifyPropertyChanged intereface implemented, I can pass event data to registered or subscribing objects.

    Important: Calling a method to update a property value like bookService.SetLoanedState(false) is a bad programming and an anti-patterns design. A property can have two accessors, get and set, and they should be used to get a value and to change a value. Methods have different roles...

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

    Hope this works...

    0 讨论(0)
提交回复
热议问题