C# - issue with custom raising events - c#

I have my class where I define my event:
public class EventRaiserUtility
{
public event EventHandler updateList;
public void updateListEvent()
{
if (updateList != null)
{
updateList(this, EventArgs.Empty);
}
}
public static EventRaiserUtility raiser = new EventRaiserUtility();
}
and this is where I raise my event:
EventRaiserUtility.raiser.updateListEvent();
and finally this is where I'm trying to create the listener:
...
EventRaiserUtility.raiser.updateList += new EventHandler(raiser_updateList);
//placed in the init method of another class
...
private void raiser_updateList(object sender, EventArgs e)
{
connType = MainWindowViewModel.getTTC();
}
Simply: this event has to notify when a list is updated and then update another list, with getTTC() with raiser_updateList.
But raiser_updateList is never called. Why? All my 3 snippets of code are in 3 different classes (same project), but this isn't a problem... right?

You're creating a new EventRaiserUtility just before you call updateListEvent (which should have a capital U to follow .NET conventions, by the way; ditto updateList => UpdateList) - but you're creating a separate EventRaiserUtility in order to subscribe to the event. They're different objects, so have different event subscribers. If you always create a new object before raising the event, there could never be any subscribers.
You should have a single EventRaiserUtility stored in an instance variable in the containing class - you'd create that on construction, then subscribe to the event in one place an raise it in another... but because they'd be talking about the same EventRaiserUtility object, you wouldn't lose the subscription.
(It's not clear that this utility class actually has much value, to be honest - why aren't you just declaring the event in your class directly? And why declare your own delegate when EventHandler has exactly the same signature?)

As far as I can see - you are subscribing to the event of one instance of EventRaiserUtility, but raising event from another instance which has no subscribers

you need one object to really own the event. Maybe that is the EventRaiserUtility, but you'd still need to make the same instance available in both classes. Without knowing the relationship between those classes

Related

How do I implement this kind of event listener design?

I am new to C# so this is probably me just not understanding something fundamental or missing out on some feature of the language. I've searched online but all the examples I seem to find have everything all in one class (in other words, they define the event as well as the method that executes when the event is triggered), which is not what I want.
For my scenario I'd like to define an interface of listener methods that can accept some custom parameters (this would be my own EventArgs right?) that provide instructions. Lets pretend its for a car, so I have methods named:
Start(MyCustomParameters par)
Accelerate(MyCustomParameters par)
Decelerate(MyCustomParameters par)
and then I want to be able to create classes that provide the actual implementation of these methods.
completely separate from all this, I have a single class that executes periodically based on an external process and I want it to be responsible for triggering these events (when the car starts and accelerates etc).
That's the basics of what I'm trying to get working but no luck so far. Also, one follow-up question. If my listener-implementation class needs to maintain any kind of state from a given call, how best to do that (e.g. say that when Accelerate is called it wants to be able to return the speed that it accelearted to back to the invoker of the event - e.g. 80 kph)
hope you can help SO, thank you very much
here is a simple example of event/listener in c# :
//your custom parameters class
public class MyCustomParameters
{
//whatever you want here...
}
//the event trigger
public class EventTrigger
{
//declaration of the delegate type
public delegate void AccelerationDelegate(MyCustomParameters parameters);
//declaration of the event
public event AccelerationDelegate Accelerate;
//the method you call to trigger the event
private void OnAccelerate(MyCustomParameters parameters)
{
//actual triggering of the events
if (Accelerate != null)
Accelerate(parameters);
}
}
//the listener
public class Listener
{
public Listener(EventTrigger trigger)
{
//the long way to subscribe to the event (to understand you create a delegate)
trigger.Accelerate += new EventTrigger.AccelerationDelegate(trigger_Accelerate);
//a shorter way to subscribe to the event which is equivalent to the statement above
trigger.Accelerate += trigger_Accelerate;
}
void trigger_Accelerate(MyCustomParameters parameters)
{
//implement event handling here
}
}
I hope it helps.

Why public event cannot be invoked outside directly?

Consider we have a class with event declared:
public class FooBar
{
public event EventHandler FooBarEvent;
}
Despite of "publicness" of the event, we cannot call FooBarEvent.Invoke from outside.
This is overcame by modyfing a class with the following approach:
public class FooBar
{
public event EventHandler FooBarEvent;
public void RaiseFooBarEvent(object sender, EventArgs eventArguments)
{
FooBarEvent.Invoke(sender, eventArguments);
}
}
Why accessing public events outside is limited by adding and removing listeners only?
Defining a public event merely gives consumers the ability to subscribe and unsubscribe from it. The ability to raise the event is limited to the type hierarchy which declares the event.
Allowing all subscribers to also be able to raise the event would be a bit chaotic. Imagine for example I had a TextBox class which had a Focused event. If any old consumer could raise the event then the Focused event could easily fire when the TextBox class wasn't actually focused. This would make it nearly impossible to maintain any type of invariant during an event.
Personally I think this is done to properly convey the design principles behind the whole events architecture.
The purpose of an event is to notify a listener of said event occurring in a given object.
What's the point of raising events of classes that don't belong to you?
That's what events are for. If you want to invoke it publicly you probably need delegates not events
Events gives encapsulation,
It prevents other classes from assigning anything to it
It prevents passing it as a parameter to methods
It prevents assigning it to any variable
It prevents calling it from another classes (not even derived classes have access to it)
etc
public accessibility tells that it can be subscribed from anywhere, not invoked from anywhere.
the answer to your question is
An event in C# is a way for a class to provide notifications to clients of that class when some interesting thing happens to an object.
Invoking the event from outside doesn't makes sense therefore it is not allowed.
I think you should change your perspective on how events work. Other classes shouldn't "own" the event and trigger it. Classes which "listen" to the event by "subscribing" to it and do a certain action when this event occurs.
That's the way the language is defined - an event can only be fired by the owning class. If you must fire it from a different class, have the owning class define a public method that will fire the event:
public FireFooBarEvent (object sender, EventArgs args)
{
if(FooBarEvent != null)
FooBarEvent(sender, args);
}
And call this method from any class.

Confused in Events & RelayCommand (C#)

I am a beginner in Events, trying to built a MVVM......
**Question 1:
Referring to some online example of overriding a ArrayList class with events:
http://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class ListWithChangedEvent: ArrayList
{
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e) {if (Changed != null) Changed(this, e);}
...
}
Am I correct to say that if I override any class by adding an event into it, whenever any member/method inside the overrided class was changed/called, the method OnChanged will be automatically run? (and I can see it when debugging?)
**Question 2:
Sorry quite confused with what is doing inside RelayCommand. Specifically why in the EventHandler CanExecuteChanged it Add and then Remove the method from the ConfigurationManager simultaneously?
Thanks in advance.
As for your 1st question, I think you misunderstand something; just adding a method called OnChanged does not have the effect you describe. As with any other method, it must be called by some other code to be executed. As the base class and its methods do not know anything about the derived class, they do not invoke the method/event - and not even "by convention" because it is named OnChange.
I'm not sure whether I understand your 2nd question correctly. The CanExecuteChanged event is used to notify the UI that something has changed that influences whether a command can or cannot be executed. I don't know your code or the sample you are referring to in regards to ConfigurationManager, but removing and adding an event handler is generally done in order to assert that an event handler is registered exactly once. If you register an event handler several times, it is called multiple times - a behavior one would rarely want. Therefore one removes the event handler before registering it anew.

Calling private event handler from outside class

i've two classes.
One class (say A) takes a textbox in c'tor. and registers TextChanged event with private event-handler method.
2nd class (say B) creates the object of class A by providing a textbox.
how to invoke the private event handler of class A from class B?
it also registers the MouseClick event.
is there any way to invoke private eventhandlers?
Short answer: don't.
Declare your event handler as public or, better yet, create a public proxy method, like
public class MyClass
{
private myHandler....
public returnType DoClick() { return myHandler(...); }
}
Giving direct access to a private member defeats the purpose of declaring it private.
Create a public method that both the event handler and the other class can call. In general, it's a bad idea to call event handlers directly. Think carefully about what you're trying to do and you should be able to find a code structure that more closely matches the concept of what you're trying to do. You don't want your other class to click a button; you want your other class to do something that clicking a button will also do.
there is no restriction on both subscribing with private method and firing event with private subscriber. Did you have any errors so far?

Clear All Event subscriptions (Clone linked)

I just implemented Clone from ICloneable and realized that the event subscriptions from my source instance also followed. Is there a good way to clear all those?
Currently I am using a couple of these loops for every event I have to clear everything.
foreach (var eventhandler in OnIdChanged.GetInvocationList())
{
OnIdChanged -= (ItemEventHandler) eventhandler;
}
foreach (var eventhandler in OnNameChanged.GetInvocationList())
{
...
This works fine but clutters the code a bit. Mostly worried to get event dangling.
I think you could just set OnIdChanged = null in your cloned object.
After you have created the clone you just call the ClearEvents method on the clone.
public class ClonedObject
{
public event EventHandler OnIdChanged;
public event EventHandler OnNameChanged;
public void ClearEvents()
{
OnIdChanged = null;
OnNameChanged = null;
}
}
Presumably, if you truly wanted to clone an object, you wanted to keep those event subscriptions.
If you're cloning objects that shouldn't be subscribed to events, it appears you should consider refactoring your code. Have your controller or similar objects subscribe to the events with a reference to a dedicated data object and have your data objects store that data without referencing the events; clone the data objects and place them in appropriate controller objects as necessary.
Ultimately, I'm suggesting you get around the issue by not subscribing to events to which you don't need to subscribe. Look at the problem space from a different angle.

Categories