As mentioned at the end of Part 6, in this post I want to show how you can use in your Blazor Server web app project C# events, delegates and the EventCallback<T> class.

More about C# events and delegates you can read in my following post.


In Part 6 I was showing how you can query the on-premise Active Directory for more information about the signed-in user. These information I am using in the footer (separate razor component BC_Footer.razor) of my time tracking and vacation planning web app.

In this web app I also have a feature, where users with admin privileges can impersonate other users, therefore the information displayed in the footer (BC_Footer.razor component) should be refreshed into the impersonated users information.

By the way, the <select> box you see below on the user impersonation page, is the hybrid of a textbox and <select> box. It’s jQuery-based and it’s useful for tagging, contact lists, country selectors, and so on.

More about in my next posts and the following link.

Selectize
https://selectize.dev/





Events and Delegates for C# Classes used in Blazor Server

The information about the user will be stored in properties from the BcActiveDirectory class (service) and be rendered on the web app’s footer when the BC_Footer.razor component is initialized the first time the page is loaded by calling the OnInitializedAsync() task as shown below.

 protected override async Task OnInitializedAsync()
    {

        // sAMAccountName
        Username = BcAD.Login;
        UserPrincipalName = BcAD.UserPrincipalName;
        EMail = BcAD.Email;
        Telefon = BcAD.TELEPHONE;
        Mobil = BcAD.MOBILE;
        Buero = BcAD.OFFICE_NAME;
        Firstname = BcAD.Firstname;
        Name = BcAD.Name;
        BrainNr = BcAD.BRAIN_NR;
        Title = BcAD.TITLE;
        Birthday = BcAD.BIRTHDAY;
        MANAGER = BcAD.MANAGER;
        whenCreated = BcAD.whenCreated;
        ErsterArbeitstag = BcAD.ErsterArbeitstag;

        Vorname = BcAD.Firstname;
        Nachname = BcAD.Name;
        BRAIN_NR = BcAD.BRAIN_NR;

    }


Here you can see the footer in black (BC_Footer.razor component) with the information about the signed-in user and queried from the on-premise Active Directory.


If now the signed-in user is changed because of a user impersonation, the information from the new user will not be rendered in the footer, even the new information are set in the properties from the BcActiveDirectory class (service), because the footer is alread rendered the first time the page is loaded with the OnInitializedAsync() task.

In order to inform the BC_Footer.razor component, that its state has changed, we need to execute the StateHasChanged() method when the properties in our BcActiveDirectory class (service) have changed.


Therefore we can use C# events and delegates to inform the BC_Footer.razor component, when properties in our BcActiveDirectory class (service) have changed and therefore the StateHasChanged() method should be executed.


We can use events and delegates if an event raises in one class named for example class A, which is completely decoupled from another class B for example.

Now class B should react and execute code (a method) if in class A an event is raised. Therefore you can use events and delegates to inform class B and to execute a method within.

In my web app the event that is raised, is that some properties from the BcActiveDirectory class (service) have changed/updated which the BC_Footer.razor component is using.

The BC_Footer.razor component in that case is not updating its state by default and we first need to inform the component, that an event was raised (properties have changed) in order to execute the StateHasChanged() method to update the state of the component.


First I will add a delegate and event to my BcActiveDirectory class as shown below.

The complete code from the BcActiveDirectory class you can see in Part 6 but without the delegate and event.

// Delegate
public delegate void RefreshStateEventHandler();
// Event
public event RefreshStateEventHandler PropertiesChanged;

using System.DirectoryServices;

namespace BlazorApp1.Data
{


    // Delegate
    public delegate void RefreshStateEventHandler();


    public class BcActiveDirectory
    {

        #region " PROPERTIES "

        public string Login { get; set; }
        public string UserPrincipalName { get; set; }

        .......

        .......

        // Event
        public event RefreshStateEventHandler PropertiesChanged;


Second I will add the following code to the SetADUserInformation(string User) method at the end.

OnADPropertiesChanged();

  public async void SetADUserInformation(string User)
        {

            string UserLogin;
            System.DirectoryServices.SearchResultCollection results = null;
            System.DirectoryServices.DirectorySearcher searcher = new();
            DirectoryEntry root = GetDirectoryEntry(ADServerIP, OU, TopLevelDomain, Domain, ADMINUSER, ADMINKENNWORT);
            searcher.SearchRoot = root;

            .......
            .......
            .......


            // Call the method which will raise the event
            OnADPropertiesChanged();


}


This will call the event publisher method below which we also need to add. This method will finally raise the event.

// Event Publisher Method
protected virtual void OnADPropertiesChanged()
{

     PropertiesChanged?.Invoke(this, EventArgs.Empty);

}


More about the null-conditional operator (?.) in the method above, you will find in my following post.



Now I need to subscribe the event from the BcActiveDirectory class in my BC_Footer.razor component and its OnInitializedAsync() task as shown below.

BcAD.PropertiesChanged += BcActiveDirectory_RefreshState;

 protected override async Task OnInitializedAsync()
    {
        // Subscribe event after login (AD) information is changed
        BcAD.PropertiesChanged += BcActiveDirectory_RefreshState;

        // sAMAccountName
        Username = BcAD.Login;
        UserPrincipalName = BcAD.UserPrincipalName;
        EMail = BcAD.Email;
        Telefon = BcAD.TELEPHONE;
        Mobil = BcAD.MOBILE;
        Buero = BcAD.OFFICE_NAME;
        Firstname = BcAD.Firstname;
        Name = BcAD.Name;
        BrainNr = BcAD.BRAIN_NR;
        Title = BcAD.TITLE;
        Birthday = BcAD.BIRTHDAY;
        MANAGER = BcAD.MANAGER;
        whenCreated = BcAD.whenCreated;
        ErsterArbeitstag = BcAD.ErsterArbeitstag;


        Vorname = BcAD.Firstname;
        Nachname = BcAD.Name;
        BRAIN_NR = BcAD.BRAIN_NR;

    }


So what happens when we subscribe the event handler with the following code line as shown above.

BcAD.PropertiesChanged += BcActiveDirectory_RefreshState;


This line will assign the start address for the BcActiveDirectory_RefreshState method in the BC_Footer.razor component and shown below, to the PropertiesChanged event which is also a delegate and in the BcActiveDirectory class.

This start address then is stored in the BcActiveDirectory class and used if the event is raised to call the assigned method.

public void BcActiveDirectory_RefreshState(object sender, EventArgs e)
    {
        InvokeAsync(() =>
         {
             StateHasChanged();
         });

    }


From now on if I will impersonate a user, also the information in the footer will gets updated.



EventHandler for C# Classes used in Blazor Server

.NET also provides an EventHandler to simplify the event declaration where we not have to create a separate delegate and event as shown above.

The EventHandler shown below will replace the delegate and event we used previously in our BcActiveDirectory class.

public EventHandler PropertiesChanged;

using System.DirectoryServices;

namespace BlazorApp1.Data
{

    public class BcActiveDirectory
    {

        #region " PROPERTIES "

        public string Login { get; set; }
        public string UserPrincipalName { get; set; }

        .......

        .......

        // Event Handler
        public EventHandler PropertiesChanged;


More about this delegate type in .NET called EventHandler you will find in my following post under Simplify the Event declaration.





Handle Component Events by using the EventCallback<T> Class

Both methods shown above with the delegates and events or the EventHandler, can be used to notify consumers (subscribers), here our BC_Footer.razor component, that an event was raised in an injected C# class and to execute therefore a method in the component to react on this event.

But what if an event is raised in a razor component?


Therefore we can use the EventCallback<T> class which is a special Blazor class that can be exposed as a Parameter so that components can easily notify consumers when something of interest has occurred.

The following article will show in detail how you can use the EventCallback<T> class by using the default blazor server template web app.

Component events
https://blazor-university.com/components/component-events/


First we need to declare a new callback parameter to the /pages/Counter.razor page and decorate it with the [Parameter] attribute.

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

This declares a new EventCallback named OnMultipleOfThree that any consuming component can register an interest in. The <int> specifies that the value emitted by the event callback will be a System.Int32.

Source: https://blazor-university.com/components/component-events/


We stay in the /pages/Counter.razor file and edit the IncrementCount method to raise an event when the counter is incremented to a multiple of 3.

private async Task IncrementCount()
{
  currentCount++;
  if (currentCount % 3 == 0)
    await OnMultipleOfThree.InvokeAsync(currentCount);
}


Finally we subscribe in the /Pages/Index.razor page to the new EventCallback. Therefore we embed the Counter component and subscribe to its OnMultipleOfThree event.

@page "/"

Last multiple of three = @LastMultipleOfThree


@* Embeds the Counter component and sets its OnMultipleOfThree event to execute 
   the UpdateLastMultipleOfThreeValue method when the event is emitted. *@
<Counter OnMultipleOfThree=@UpdateLastMultipleOfThreeValue />


@code{

    int LastMultipleOfThree = 0;

    // The value received from the event is used to update the value of LastMultipleOfThree.
    private void UpdateLastMultipleOfThreeValue(int value)
    {
        LastMultipleOfThree = value;
    }



}


Two more examples about raise an event in a razor component by using the EventCallback<T> Class, you will find in my following two posts about creating a toggle switch and toggle button component.

Here an event is raised if the state of the toggle elements changes to notify the parent component about.



More about the EventCallback<T> Class you will find in the following article.

Component events
https://blazor-university.com/components/component-events






Blazor Server Series

Blazor Server – Basics Part 1
https://blog.matrixpost.net/blazor-server-basics-part-i/

Blazor Server – Basics Part 2
https://blog.matrixpost.net/blazor-server-basics-part-ii/

Blazor Server – Basics Part 3 – Custom Layout
https://blog.matrixpost.net/blazor-server-basics-part-iii-custom-layout/

Blazor Server – Basics Part 4 – Program.cs File
https://blog.matrixpost.net/blazor-server-basics-part-iv-program-cs-file/

Blazor Server – Basics Part 5 – Authentication and Authorization
https://blog.matrixpost.net/blazor-server-basics-part-v-authentication-and-authorization/

Blazor Server – Basics Part 6 – Query the on-premise Active Directory
https://blog.matrixpost.net/blazor-server-basics-part-vi-query-the-on-premise-active-directory/

Blazor Server – Basics Part 7 – C# Events, Delegates and the EventCallback Class
https://blog.matrixpost.net/blazor-server-basics-part-vii-c-events-and-delegates/

Blazor Server – Basics Part 8 – JavaScript interoperability (JS interop)
https://blog.matrixpost.net/blazor-server-basics-part-viii-javascript-interoperability-js-interop/

Blazor Server – Basics Part 9 – Responsive Tags and Chips
https://blog.matrixpost.net/blazor-server-basics-part-ix-responsive-tags-and-chips/

Blazor Server – Basics Part 10 – MS SQL Server Access and Data Binding
https://blog.matrixpost.net/blazor-server-basics-part-10-ms-sql-server-access-and-data-binding/

Blazor Server – Basics Part 11 – Create a Native Blazor UI Toggle Switch Component
https://blog.matrixpost.net/blazor-server-basics-part-11-native-blazor-toggle-switch-by-using-the-eventcallback-class-and-css/

Blazor Server – Basics Part 12 – Create a Native Blazor UI Toggle Button Component
https://blog.matrixpost.net/blazor-server-basics-part-12-create-a-native-blazor-ui-toggle-button-component/





Links

Component events
https://blazor-university.com/components/component-events/

Events (C# Programming Guide)
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/

Delegates (C# Programming Guide)
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/

State changes (StateHasChanged)
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-3.1#state-changes-statehaschange