Creating a Blazor Layout

Any content you intend to act as a layout template for pages must descend from the LayoutComponentBaseclass. To indicate where you want the content of your page to appear you simply output the contents of the Body property.

@inherits LayoutComponentBase
<div class="main">
  <header>
    <h1>This is the header</h1>
  </header>
  <div class="content">
    @Body
  </div>
  <footer>
    This is the footer
  </footer>
</div>

References
https://blazor-university.com/layouts/creating-a-blazor-layout/
https://blazor-university.com/layouts/using-layouts/

Component Virtualization in ASP.NET Core Blazor

Virtualization is a technique that helps you to process and render only the items that are currently visible on the page (in the content viewport). We can use this technique when dealing with large amounts of data, where processing all the data and displaying the result will take time.

<div style="height:400px; overflow-y:scroll">
    <Virtualize Items="@allBooks">
        <BookSummary @key="book.BookId" Details="@book.Summary" />
    </Virtualize>
</div
<Virtualize Context="employee" ItemsProvider="@LoadEmployees">
    <p>
        @employee.FirstName @employee.LastName has the 
        job title of @employee.JobTitle.
    </p>
</Virtualize>
<Virtualize Context="employee" Items="@employees" ItemSize="25">
    ...
</Virtualize>
<Virtualize Context="employee" Items="@employees" OverscanCount="4">
    ...
</Virtualize>

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/components/virtualization?view=aspnetcore-6.0
https://www.syncfusion.com/blogs/post/7-features-of-blazor-that-make-it-an-outstanding-framework-for-web-development.aspx/amp
https://www.syncfusion.com/blogs/post/asp-net-core-blazor-component-virtualization-in-net-5.aspx

Cancel Background long-running Tasks when a user navigates to another page in Blazor

@page "/State"
@implements IDisposable

<h3>State</h3>

<p>@output</p>

@code {
    private string output = "";
    private CancellationTokenSource cts = new();
    
    protected override async Task OnInitializedAsync()
    {
        while (!cts.IsCancellationRequested)
        {
            await Task.Delay(1000);
            var rnd = new Random();
            output = rnd.Next(1, 50).ToString();
            StateHasChanged();
        }
        
        // cts.Token.ThrowIfCancellationRequested();
    }
    
    public void Dispose()
    {
        cts.Cancel();
        cts.Dispose();
    }
}

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-6.0#cancelable-background-work
https://www.syncfusion.com/faq/blazor/web-api/how-do-i-cancel-background-long-running-tasks-when-a-user-navigates-to-another-page-in-blazor

Refresh a Blazor Component with StateHasChanged

@page "/State"
<h3>State</h3>

<p>@output</p>

@code {
    private string output = "";
    
    protected override async Task OnInitializedAsync()
    {
        while (true)
        {
            await Task.Delay(1000);
            var rnd = new Random();
            output = rnd.Next(1, 50).ToString();
            StateHasChanged();
        }
    }
}

References
https://www.techiediaries.com/refresh-blazor-component-statehaschanged-invokeasync/
https://docs.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-6.0#state-changes-statehaschanged

Optimizing Blazor performance using the @key directive

The @key directive is important when creating components dynamically by iterating list/IEnumerable. Adding the @key will ensure proper change detection and UI update in the collection of components.

<ul class="mt-5">
    @foreach (var person in People)
    {
        <li @key="person.Id">@person.Id, @person.Name</li>
    }
</ul>

Tip: Always use @key for components that are generated in a loop at runtime.

References
https://blazor-university.com/components/render-trees/optimising-using-key/
https://www.meziantou.net/optimizing-blazor-performance-using-the-key-directive.htm
https://www.syncfusion.com/faq/blazor/components/what-is-the-use-of-key-property

Get the Reference or Instance of a Component in ASP.NET Core Blazor

o capture a component reference in Blazor, use the @ref directive attribute. The value of the attribute should match the name of a settable field with the same type as the referenced component.

<MyLoginDialog @ref="loginDialog" ... />

@code {
    MyLoginDialog loginDialog;

    void OnSomething()
    {
        loginDialog.Show();
    }
}

References
https://docs.microsoft.com/en-us/dotnet/architecture/blazor-for-web-forms-developers/components#capture-component-references
https://www.syncfusion.com/faq/blazor/components/how-do-i-get-the-reference-or-instance-of-a-component

Two-way Binding in Blazor Component

We need to tell Blazor that the consuming page wants to use two-way binding.To use two-way binding on a parameter simply prefix the HTML attribute with the text @bind-. This tells Blazor it should not only push changes to the component, but should also observe the component for any changes and update its own state accordingly.

Two-way binding in Blazor uses a naming convention. If we want to bind to a property named SomeProperty, then we need an event call-back named SomeProperyChanged. This call-back must be invoked any time the component updates SomeProperty.

SecondComponent.razor

<h3>SecondComponent</h3>

<button @onclick="Callback">Increment</button>

@code {

    [Parameter]
    public int CounterValue { get; set; }

    [Parameter]
    public EventCallback<int> CounterValueChanged { get; set; }

    private async Task Callback()
    {
        if (CounterValue >= 20)
        {
    // reset counter
            CounterValue = 0;
        }
        else
        {
            CounterValue++;
        }

    // fire event
        await CounterValueChanged.InvokeAsync(CounterValue);
    }

}

Counter.razor

@page "/counter"

<SecondComponent @bind-CounterValue="counter"></SecondComponent>

<p>@counter</p>

@code
{
    private int counter = 2;
}

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/components/data-binding?view=aspnetcore-6.0#binding-with-component-parameters
https://blazor-university.com/components/two-way-binding/
https://stackoverflow.com/questions/57932850/how-to-make-two-way-binding-on-blazor-component

Communicate Between Components in Blazor using Events

TestComponent.razor

<h3>TestComponent</h3>

<p><button @onclick="Button1_Clicked">Button1</button></p>
<p><button @onclick="Button2_Clicked">Button2</button></p>

@code {
    
    [Parameter]
    public EventCallback Event1 { get; set; }
    
    [Parameter]
    public EventCallback<TestModel> Event2 { get; set; }

    private void Button1_Clicked(MouseEventArgs obj)
    {
        Event1.InvokeAsync("Event1 is fired");
    }

    private void Button2_Clicked(MouseEventArgs obj)
    {
        Event2.InvokeAsync(new TestModel() {Message = "Event2 is fired", Date = DateTime.Now});
    }
}

TestModel.cs

namespace BlazorApp1;

public class TestModel
{
    public DateTime Date { get; set; }
    
    public string Message { get; set; }
}

Index.razor

@page "/"

<TestComponent Event1="Callback" Event2="Callback2"></TestComponent>

<div>@((MarkupString) output)</div>

@code {
    private string output = "";

    private void Callback2(TestModel obj)
    {
        output += "<p>" + obj.Message + ", ";
        output += obj.Date +"</p>";
    }

    private void Callback(object obj)
    {
        output += "<p>"+obj+"</p>";
    }
}

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/components/event-handling?view=aspnetcore-6.0#eventcallback
https://blazor-university.com/components/component-events/
https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/