1

I am using event to pass data from one partial view to another in Blazor.

Problem: the dispose is not working and every time when page destroyed and re rendered it attaches the same event. And when ever I invoke event it invokes multiple time(that number of time when partial view destroyed and recreated)

Event definition code with invoke method

public event Action<long,long,bool,bool> MyEvent;
public void InVokeMyEvent(long data1,
        bool data2,long data3,bool data4) {
        MyEvent?.Invoke(data1,data2,data3, data4);
    } 

The function definition

async Task MyFunction(long data1,
        long data2,
        bool data3,
        bool data4)
{}

I am registering the event in OnInitializedAsync function as following.

protected override async Task OnInitializedAsync()
{

    RGEState.MyEvent+= async (long data1,
       long data2,
       bool data3,
       bool data4) =>
   await MyFunction(data1,
        data2,
        data3,
        data4);

    await base.OnInitializedAsync();
}

Now to detach event I am doing following code in page after implementing IDisposable.

public void Dispose()
{
    RGEState.MyEvent -= async (long data1,
       long data2,
       bool data3,
       bool data4) =>
   await MyFunction(data1,
        data2,
        data3,
        data4);
}
IPS
  • 417
  • 9
  • 22
  • I know this seems silly but does your component implement `IDisposable` via the `@implements` directive? – Rich Bryant Feb 27 '20 at 08:50
  • 1
    Yes, I have already implemented IDisposable via the @Implements directive. – IPS Feb 27 '20 at 08:59
  • 2
    is there any reason why your Event is async? In general, Events cannot be awaited. – Rich Bryant Feb 27 '20 at 10:11
  • This method calls database to get some data. I want to display process indicator(Loader) while database called occurred so I made this method async and by using a Boolean variable true/false with StateHasChanged method I can easily display hide loader. – IPS Feb 27 '20 at 10:19

3 Answers3

3

This question has been answered here by Jon Skeet How to remove a lambda event handler

Basically create a delegate and use that to subscribe/unsubscribe the event.

Edited to help the OP understand

Like this - you need to hold a reference to your expression so that when you unsubscribe it is the same delegate.

private Action<long,long,bool,bool> _delegate;
protected override async Task OnInitializedAsync()
{

    _delegate = async (long data1,
       long data2,
       bool data3,
       bool data4) => await MyFunction(data1,
        data2,
        data3,
        data4);

    RGEState.MyEvent += _delegate;
    await base.OnInitializedAsync();
}

public void Dispose()
{
    RGEState.MyEvent -= _delegate;
}
Mister Magoo
  • 7,452
  • 1
  • 20
  • 35
  • Thank you for replying, I am doing same and its working fine with sync method but its not working with Async method as it does not unsubscribe event on IDisposable. – IPS Feb 27 '20 at 12:09
  • 2
    Well your code above doesn't show you doing that - perhaps you could update it with that code? – Mister Magoo Feb 27 '20 at 12:18
1

I'm not sure I understand what is the issue. This behavior is by design... When your component is created, the OnInitializedAsync method is executed, and it attaches an event handler to MyEvent event. When the component is destroyed, the event handler is detached. If your component is recreated, the process described above is repeated again... and again. Do you want the event handler to be added only once ? Is that what you want ? Perhaps you should design your components in a different way.

However, perhaps implementing the CircuitHandler object can solve your issue, as this deals with the life cycle of the Circuit connection. See my answer here how to do it...

enet
  • 41,195
  • 5
  • 76
  • 113
0

See following example

As per above link I made function "MyFunction" sync and called another async function inside of it for loader

void MyFunction(long data1,
        long data2,
        bool data3,
        bool data4)
{
   InvokeAsync(async () => { await SecondFunction(data1, data2, data3, data4); });
}
async Task SecondFunction(long data1,
        long data2,
        bool data3,
        bool data4)
{
 isLaoder = True;
 StateHasChanged ();

/****Calling DB ***/

isLaoder = False;
StateHasChanged ();
}
IPS
  • 417
  • 9
  • 22