Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Blazor child component event handling

Using .Net 7 and Blazor server, I am trying to build a message viewer using a Message component and a List<Message> as a class library to reuse across all apps in my environment. Everything works fine except for the ability to remove the Message component from the list. The Message razor class looks like

@namespace TestApp.Components

@if(MessageText!=null){
    <div class="mt-3 @MessageClass">
        @MessageText
        <button class="btn-close" @onclick="CloseMessage">Close</button>
    </div>
}

and the relevant parts of the code behind are as such:

using Microsoft.AspNetCore.Components;

namespace TestApp.Components;
public partial class Message : ComponentBase
{
    public string MessageText {get;set;} = string.Empty;
    public string MessageClass {get;set;} = string.Empty;
    public Guid MessageId {get;set;} = new Guid();
    [Parameter] public Message Origin {set{
        MessageText=value.MessageText;
        MessageClass=value.MessageClass;
        MessageId=value.MessageId;
    }}
    public Message(){

    }
    public Message(string message){
        MessageText=message;
    }
    public event EventHandler CloseRequested=default!;

    private void CloseMessage()
    {
        CloseRequested(this,EventArgs.Empty);
    }
}

This is all then referenced in an application state class that holds the list of messages per user, until they are dismissed. That code looks like

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

using TestApp.Components;

public class ApplicationState
{
    public List<Message> Messages {get;set;} = new();
    public event EventHandler OnMessagesChange = default!;

    public void AddMessage(string messageText)
    {
        var message = new Message(messageText);
        Messages.Add(message);
        EventHandler handler = OnMessagesChange;
        if(handler!=null)
            handler.Invoke(this,EventArgs.Empty);
        message.CloseRequested+=RemoveMessage;
    }

    private void RemoveMessage(object sender, EventArgs e)
    {
        var message = (Message?)sender;
        if(message!=null)
            Messages.Remove(message);
    }
}

When I click the button to remove the message, I get the error System.NullReferenceException: Object reference not set to an instance of an object. which I understand to mean that the EventHandler is initialized but I can’t figure out why it isn’t since the ApplicationState class subscribes to that event and therefore it should be invokable.

I’ve tried null checking the event handler in the CloseMessage method as well as setting the event handler to =default!; with no success. Any help would be appreciated.

>Solution :

You have

  var message = new Message(messageText); // new() of a Component
  ...
  message.CloseRequested+=RemoveMessage;

and

… a foreach loop in a razor page. Inside that loop, it uses the component to with the Origin property to set the values.

This means that you have 2 Components for each message: 1 in the list, with the event set and 1 created by the foreach loop. You copy the properties but not the event.

The instance from the foreach loop will be the one shown, and that has eventCloseRequested == null

The solution is to split this in a MessageComponent : ComponentBase and a MessageViewModel. Then it is at least clearer what is going on.

I leave the event handling open, there are many ways to do that. But you’ll also want to update the parent page when you remove a message. So I would add an EventCallback param to the component and assign an update method on that page.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading