Question

How can I launch an event that has accessors like this :

public event EventHandler CanExecuteChanged
    {
      add
      {
        CommandManager.RequerySuggested += value;
      }
      remove
      {
        CommandManager.RequerySuggested -= value;
      }
    }

If it were a normal event I would launch it by:

CanExecuteChanged(sender, EventArgs..). 

But here it doesn't work - I can only do

CanExecuteChanged +=..

to attach a method do the event - but I can't Launch it.

Also some documentation on the subject would be appreciated. Thanks.

EDIT The event is from class implementing ICommand in WPF. there's nothing more to show :). And no - the CommandManager.RequerySuggested(this, EventArgs.Empty); doesn't work.

EDIT2 Not sure what to say - Jon's example should have worked yet even if the add method is called correctly - when I try to call the event - it's null :|. I probably will drop events with accessors.

Was it helpful?

Solution

That event is just subscribing to and unsubscribing from another event. If you want your subscribers (and only your subscribers - not separate ones to the other event) to be invoked, you'll need to keep hold of your subscribers separately. For instance, you could change the code to something like:

private EventHandler canExecuteChanged;

public event EventHandler CanExecuteChanged
{
    add
    {
        CommandManager.RequerySuggested += value;
        canExecuteChanged += value;
    }
    remove
    {
        CommandManager.RequerySuggested -= value;
        canExecuteChanged -= value;
    }
}

OTHER TIPS

I think you have events confused with delegates. Only the class exposing the event can raise it... Others can only subscribe-unsubscribe to it. If you are invoking the event from within the class declaring the event, it should work like a regular delegate.

The best page I could find on Events vs Delegates. Read up..

Can you post a bigger snippet.. something seems amiss..

Killer Update

I think I finally see your problem and how to solve it. Short Answer: It does not know the name of delegate to invoke if you write your own accessors. If you don't.. the compiler adds the private delegate of known name and hence is able to invoke it

This code snippet shows what I mean. This MSDN article showed me the light. Great question dude.. I lost 30 mins. Upvoted :)

public class Hash1 
    {

        private EventHandler myHomeMadeDelegate;
        public event EventHandler FancyEvent
        {
            add
            {
                //myDelegate += value;
                myHomeMadeDelegate = (EventHandler)Delegate.Combine(myHomeMadeDelegate, value);
            }
            remove
            {
                //myDelegate -= value;
                myHomeMadeDelegate = (EventHandler)Delegate.Remove(myHomeMadeDelegate, value);
            }
        }
        public event EventHandler PlainEvent;


        public Hash1()
        {
            FancyEvent += new EventHandler(On_Hash1_FancyEvent);
            PlainEvent += new EventHandler(On_Hash1_PlainEvent);

            // FancyEvent(this, EventArgs.Empty);  //won't work:What is the backing delegate called? I don't know
            myHomeMadeDelegate(this, EventArgs.Empty); // Aha!
            PlainEvent(this, EventArgs.Empty);
        }

        void On_Hash1_PlainEvent(object sender, EventArgs e)
        {
            Console.WriteLine("Bang Bang!");
        }

        void On_Hash1_FancyEvent(object sender, EventArgs e)
        {
            Console.WriteLine("Bang!");
        }
}

Ok, I found that if I want to trigger that event you have to do :

CommandManager.InvalidateRequerySuggested();.

You've got to invoke the underlying events directly. In your case, it looks as though this would be:

<blockquote>CommandManager.RequerySuggested(sender, EventArgs.…)</blockquote>

/EDIT: Ok, I didn't notice that CommandManager is a framework class. In this case, you obviously don't want to do what I've proposed. Jon's solution is to the point: You've got to keep track of your own event and invoke that (e.g. as a delegate). In keeping with Jon's example, invocation would look like this:

canExecuteChanged(sender, EventArgs.Empty);

wow, just had similar problems. The answer that helped me understand is somewhat like Gishu's.

Also from the C# specs, http://www.microsoft.com/en-us/download/details.aspx?id=7029, under "10.8.1 Field-like events" it says "When compiling a field-like event, the compiler automatically creates storage to hold the delegate,"

specs also says:

Thus, an instance event declaration of the form:

class X
{
   public event D Ev;
}

could be compiled to something equivalent to:

class X
{
   private D __Ev;  // field to hold the delegate

   public event D Ev {
      add {
         lock(this) { __Ev = __Ev + value; }
      }

      remove {
         lock(this) { __Ev = __Ev - value; }
      }
   }
}

If you do something like the code below, the compiler compiles it successfully:

namespace ConsoleApplication1
{    
    class Program 
    {
        public event EventHandler ss;

        Program()
        {
            if (null != ss)
            {
                ss(this, EventArgs.Empty) ;

            }
        }

        static void Main(string[] args)
        {
            new Program();
        }
    }
}

And if you add accessors to ss above, it will NOT compile:

namespace ConsoleApplication1
{    
    class Program 
    {
        public event EventHandler ss
        {
            add { }
            remove { }
        }

        Program()
        {
            if (null != ss)
            {
                ss(this, EventArgs.Empty) ;

            }
        }

        static void Main(string[] args)
        {
            new Program();
        }
    }
}

There are two kinds of events demonstrated here

  1. Field-like events => we can invoke
  2. events with accessors => we cannot invoke (cannot find this in specs why, maybe I missed it)(and was only testing this on Visual Studio 2005, and the specs was the latest, I guess)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top