0

Is it possible to do something like this:

EventHandler handler = null;
handler = (s, args) =>
{
    DoStuff();
    something.SomeEvent -= handler;
};
something.SomeEvent += handler;

with Prism's EventAggregator? ie

Action subscriber = null;
subscriber = () =>
{
    DoStuff();
    EventAggregator.GetEvent<SomeEvent>().Unsubscribe(subscriber);
};
EventAggregator.GetEvent<SomeEvent>().Subscribe(subscriber);

2 Answers2

1

Subscribe returns a subscription object which you can dispose to unsubscribe:

IDisposable subscription = null;
subscription = eventAggregator.GetEvent<SomeEvent>().Subscribe( () =>
                                                                {
                                                                    // do something
                                                                    subscription.Dispose();
                                                                } );
Haukinger
  • 10,420
  • 2
  • 15
  • 28
  • That's exactly what I'm doing; but so long as an object declared outside the anonymous method is within that method, the method is never called. So I'm at a loss why it's not working for me. I even copied your code into mine. The anonymous method doesn't get called until I comment out the line referencing "subscription" –  Jul 13 '20 at 18:05
0

Yes, that will work with Prism's event aggregator, too. It all comes down to comparing delegates for equality in both examples. Refering to a delegate inside of the anyonymous method is not specific to the event aggregator.

However, you should be aware that while using anonymous methods for this kind of one-time event handling is working, because you hold on to the delegate instance handler or subscriber, subscribing to and unsubscribing from anonymous methods can be quite challenging in more complex scenarios. You should have have a look at these two questions for understanding how delegate comparison works for anonymous methods.

As alternatives to using an anonymous method, you could either use instance methods or local functions that were introduced in C# 7.0, like in the following example.

private void AddEventHandler()
{
   // Local method to replace your anonymous method
   void DoStuffAndUnsubscribe()
   {
      DoStuff();
      eventAggregator.GetEvent<SomeEvent>().Unsubscribe(DoStuffAndUnsubscribe);
   }

   eventAggregator.GetEvent<SomeEvent>().Subscribe(DoStuffAndUnsubscribe);
}

As @Haukinger pointed out, the most concise way is to capture an instance of the subscription token of the event in the anonymous method to unsubscribe using Dispose().

IDisposable subscriptionToken = null;
subscriptionToken = eventAggregator.GetEvent<SomeEvent>().Subscribe(() =>
{
    DoStuff();
    subscriptionToken.Dispose();
});
thatguy
  • 21,059
  • 6
  • 30
  • 40
  • This is overly complicated, you can just dispose the subscription (the value returned from `Subscribe`) to unsubscribe. – Haukinger Jul 11 '20 at 18:41
  • Thanks, I thought of subscription tokens, but missed capturing them in a lambda. Have an upvote. – thatguy Jul 13 '20 at 07:13
  • I've noticed that local functions can only access value-types from the containing method, not reference type. Is that how it's supposed to work or am i doing something wrong? –  Jul 13 '20 at 22:41
  • @JamesDePaola I have tested all of the above methods to ensure that they are working. A local function can capture instance state, method arguments or local variables, it should not be restricted to value types only. Just try to create a local `object` and refer to it in the local method, that should work just fine. – thatguy Jul 14 '20 at 09:08
  • @thatguy This is what I'm using: ```int x = 1; object y = new TextBox(); IDisposable subscriptionToken = null; subscriptionToken = this.EventAggregator.GetEvent().Subscribe((args) => { //x = 6; //y = new CheckBox(); System.Diagnostics.Debugger.Break(); //subscriptionToken.Dispose(); });``` Once I uncomment any of those lines, even just "x=6;", the anonymous method is simply never called. –  Jul 14 '20 at 21:52
  • @thatguy And that's just for anonymous method. I only got local method to work using a work around. Cause this: ```SubscriptionToken token = null; token= this.EventAggregator.GetEvent().Subscribe(LocalMethod); void LocalMethod(SelectedDataObjectIDArgs args) { this.EventAggregator.GetEvent().Unsubscribe(token);``` while it compiles, it never gets called. –  Jul 14 '20 at 21:58