Using dotnet 3.1.100-preview2-014569
Ok consider the following example:
Create a new Blazor WebAssemply project from template, then add the following:
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;
}
}
What happens:
Expected behavior: When clicking on the menu item Loan Book the page should show Book Loaned or if I click Return Book it should say Book returned. But this only happens if I click to another page, like Home, and then back again.
How can I force the page to re-render/re-check updated values from BookService even when it's on the same page already?
Thanks!
A page is reloaded/refreshed automatically at a specified interval using “NavigationManager” in OnAfterRender() method. Here the NavigateTo(“url”, forceLoad: true) method, is used to force load the browser based on the URI.
How do I refresh the Blazor component without reloading the page when database is updated? You can refresh the Blazor component using the SignalR concept without reloading the page. When using SignalR, saving the changes in one page notifies the changes made to other clients.
To force a component to rerender, use the “StateHasChanged” method in Blazor, to notify that the state has been changed and requires re-rendering.
Razor components can be integrated into Razor Pages and MVC apps in a hosted Blazor WebAssembly solution. When the page or view is rendered, components can be prerendered at the same time.
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));
}
}
}
@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();
}
}
@code {
// Code removed for brevity
private void LoanBookClicked()
{
bookService.IsLoaned = true;
}
private void ReturnBookClicked()
{
bookService.IsLoaned = false;
}
}
Hope this works...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With