One common thing I see developers doing in WinForms is forms/controls subscribing to their own events so you get
this.Load += new System.EventHandler(this.WelcomeQuickViewWF_Load);
this.Activated += new System.EventHandler(this.WelcomeQuickViewWF_Activated);
rather than
protected override void OnActivated(EventArgs e)
{
}
Now I know the second way is more Object Oriented, the first way is event driven and I tend to refactor towards overriding - is there any reason NOT to do this? What I don't want to be doing is making changes that are not really needed and purely an aesthetic choice.
By subscribing to your own event, you give up control over when your code is invoked when there are other subscribers to the event. By overriding the event raising method, you have full control over when your code should be invoked. You could invoke it before notifying subscribers or after. There's also no chance of your code being canceled on a cancelable event.
If the method is overridable, do so. Otherwise register as you have no other choice.
MSDN says that overriding the On* methods is the preferred technique for handling an event in a derived class:
The OnActivated method also allows derived classes to handle the event without attaching a delegate. Overriding this method is the preferred technique for handling the event in a derived class.
So I'd say the event handler approach is non-idiomatic.
Related
My understanding about events in C# for a console application:
create a delegate that has the same signature as the event handler method in the subscriber class.
declare an event based on this delegate
raise the event
My understanding of this step is: it is simply an wrapper function where parameters are passed to the event to invoke the event handler functions pointed to by the event.
So raising the event is just invoking the wrapper function in the publish class.
Now when I create a very simple Windows form application, I am not able to apply this general concept.
Consider a WinForms application with just one button.
// registering statement
Button1.Click += new EventHandler (this.button1_click)
I can identify the first step. It is the pre-defined System.EventHandler delegate.
Click event for the button is also pre-defined. No problem with that.
event raising step : here I fail to make the connection between a console application and an Windows application.
Where is the code kept that actually RAISES the event for a WinForms application? We don't seem to have to code it.
I understand click event is raised when someone "clicks" on the button, but how is that realized in the C# code for WinForms application?
How does the compiler "just" knows that a Click event for a button means someone clicking on a button and therefore an event should be raised?
How is click event raised? How are the parameters passed to the event?
The Control class has protected function called WndProc, when the OS needs to tell the program something it generates a Message object and passes it in to the WndProc function.
That WndProc function then looks at the message and sees what kind of message it is, if it is the "mouse left button up" message it runs the the OnClick method with the correct parameters parsed out of the Message object that was passed in to WndProc.
That OnClick method is the thing that raises the event to the subscriber.
From the soruce of .NET:
The entry point of WndProc
It detecting the message type
It parsing and calling the OnClick method
It raising the Click event
Your understanding is a bit backwards. I think this is why you have issues.
You are not creating a delegate that has the same signature as the event handler method in the subscriber class.
What you are doing is declaring what a function to which to delegate execution will look like. Here is the signature for EventHandler:
public delegate void EventHandler(object sender, EventArgs e)
So, if you want a function to be able to handle delegation of the event, it must follow that signature.
Now, the class that will delegate execution to subscribers needs a reference to those functions so it can call them when the event takes place. That is why you implement an event property. It follows then that the Button class must expose this property for you to be able to "hook" your delegates:
public event EventHandler Click
(Notice this is inherited from Control)
When you register an "event handler":
Button1.Click += new EventHandler (this.button1_click)
You are essentially saying that you want this.button1_click(object sender, EventArgs e) to fire whenever the Click event is raised by the Button1 instance.
The Button1 instance will internally decide when to fire the event at which point it will use the event property to delegate execution to the subscribed functions. It will call them with the above mentioned parameters where sender will most likely be the instance itself and the EventArgs class will give you additional information about the conditions that raised the event. The property is also usually implemented to add additional checks (like if there is anything to call in the first place).
As you can see, the code that actually raises the click is internal to the implementation of the Button (or its inheritance chain). It obviously involves mouse tracking and what not, which is the benefit of using the controls by the way, unless you want to write all that detection stuff from scratch.
A common scenerio we are running into with our current application is where we need to route and event through several classes.
Here is a sample class heirarchy.
ActionManager
MainWindow
PresentationManager
MenuManager
Menu
MenuButton
The Menu subscribes to the click event of a MenuButton. It then creates a CustomAction object and raises an event that is subscribed to MenuManager. In the MenuManager event handler it in turn raises an event that is subscribed to by the PresentationManager, and so on.
Here is a sample of what is implemented for the PresentationManager:
void MenuManager_ActionGenerated(object sender, CustomActionEventArgs e)
{
if (ActionGenerated != null)
ActionGenerated(sender, e);
}
I was hoping that there would be a way that I could raise the event at the Menu level and receive it at the ActionManager level.
Is it bad practise what I am currently doing?
You can also look into Event Aggregator. A good example can be found at codeproject: Event Aggregator with Specialized Listeners
If what you've listed as your class hierarchy is actually your visual tree, it sounds like what you are describing is Routed events.
http://msdn.microsoft.com/en-us/library/ms742806.aspx
Personally, I get scared by having a lot of events. If you are not careful with unsubscription, they can extend the lifetime of your objects. Also, they may cause tight-coupling, reducing testability. In some cases using a Commanding pattern is a better approach.
I would try this CSharpMessenger Extended.
You can write your own SubscriptionManager.
By simplifying can be a Dicationary<string, List<Action<...>>>.
The key is the event-name, value is the List of Actions to run wen that even was raised.
So all yuor components subscribe to some specified event by adding its Action<..> to the list of specified event.
And when the even raised (always via SubscriptionManager) all Action<..>s from the list will be executed.
Just a basic idea. To make this production ready you need to code a bit more.
Good luck.
I am creating a class that derives from the WPF RichTextBox control and I need to execute some code in the copy and paste events.
I understand that, whenever possible, it is best practice to implement event-based code in a derived class by overriding the base class method that raises the event. However, no such method exists in this case, so is it acceptable for my derived class to add an event handler to its own base class events?
If I do add an event handler, I assume that it should be explicitly removed when the control is disposed. However, I am not sure how best to do this in the case of RichTextBox as WPF control classes do not seem to have any mechanism for detecting disposal.
Any suggestions please?
Thanks,
Tim
Of course, you can handle events of the base class. It's commonly done for the Loaded event, for instance, since there is no OnLoaded method.
You don't need to worry about removing the handler: since the event publisher and subscriber are the same instance, not removing the handler won't prevent the GC from collecting your object.
Let's say you have a custom form MyForm : Form and want to run some custom code for the OnLoad event.
Are there any performance reasons to register for the OnLoad event and run your code in the handler method instead of overriding the OnLoad method in which you call the base method and run your custom code ?
Are there any pros/cons for going one or the other way ? What would you choose and why ?
MSDN page says this:
The OnLoad method also allows derived classes to handle the event without attaching a delegate. This is the preferred technique for handling the event in a derived class.
(emphasis mine).
From performance standpoint, the difference is negligible here. Unless you have millions of subscribers, though.
Overriding the OnLoad method allows you to run code both before and after any other handlers for the event (Which are called by base.OnLoad(e), or prevent them entirely; this can sometimes be useful.
Also, I believe that it will be a tiny bit faster.
I have my own custom control derived from System.Windows.Forms.TreeView which is present on the designer toolbox.
I add an instance of this custom control to my form (using the designer).
The purpose I created an inherited control is that I want to let the control itself handle its events since it's supposed to act as a View in a standard MVC design. I.e. when the node selection in the treeview changes I want the view to handle all interactions with the Model.
The problem is that when I add an event for my custom control (using the designer), the event gets added to my MainForm class. The only option in such case is to forward every event into my custom control, which doesn't feel very optimal.
Is there a way to control which class the event gets added to? I know it's technically possible since I can edit the auto-generated code for my MainForm and make the event being triggered into the custom control. That's clearly not the proper solution though.
Thanks.
why don't you just override some of the methods in your derived class, e.g.:
protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
{
}
Tom Frey is right. If you want the behavior on a certain event to be handled by the class that would normally fire the event, the preferred technique is to override the appropriate method that fires the event to perform your task. The eventing infrastructure is overkill and not really designed for what you're trying to do here.
The reason is that you want every instance of your view to perform these actions. You don't want these actions to be dynamically assigned and determined at runtime by things external to your view (which is what events are for).
One important thing to include when you perform such an override, however, is the call to the base's implementation. If you don't, you may encounter strange errors:
protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
{
// Do stuff you want done before here
base.OnNodeMouseClick(e);
// Do stuff you want done after here
}
Calling the base class will fire the event and may perform other actions besides. If you want something done before the event fires and any external subscribers do their thing, put it before the call to the base. If you want something done after all the events have fired and been handled, put it after. Contrived example: if your control handled some data binding, then you might want to verify the databinding exists before the call to base and you might want to verify it's valid after (in case a handler munged something).
From MSDN:
The OnNodeMouseClick method also
allows derived classes to handle the
event without attaching a delegate.
This is the preferred technique for handling the event in a derived
class.
Notes to Inheritors:
When overriding OnNodeMouseClick in
a derived class, be sure to call the
base class's OnNodeMouseClick method
so that registered delegates receive
the event.