I'm currently tasked with cleaning up, bug fixing and optimising a Form in winforms (3000 lines of code in one .cs file, it's getting a bit ugly!). I've noticed a few obvious bad practices and some redundant calls already which I could sort out relatively easily.
However there's one that is popping up a lot which seems to me like bad practice, but I can't actually back it up with any documentation. I could be completely wrong.
private void datePicker_DateChanged(object sender, EventArgs e)
{
tabControl_SelectedIndexChanged(sender, e);
}
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
tabControl_SelectedIndexChanged(sender, e);
}
My first concern is that the method will have the sender object that is the date picker or the combo box, but does this matter? I asked myself, what is the sender object there for? Perhaps this is why it's there? I also find EventArgs by itself is pretty useless as far (as I'm aware) unless the class is inherited.
I know that neither the sender or EventArgs are used in the tabControl_SelectedIndexChanged method, so the code works fine. What about possible future implications when some code is changed?
Should I change these to 3 different event handlers that all point to a simple void loadCurrentTab() method? Or perhaps I should get all 3 controls to call the same event handler, such as loadCurrentTab(sender, e)? Or just leave it as it is? Is it that important?
Should I change these to 3 different event handlers that all point to a simple void loadCurrentTab() method?
This would actually be my preference, in this scenario. This makes the intent very clear - all three event handlers are routing to one set of logic which (by design) doesn't pay attention to the sender or EventArgs.
My biggest issue with calling event handlers (aside from it being poor practice) is when you are looking at call stacks with a quick glance, in your case, you would see that the selected index of the tab changes when that did not actually happen.
It's also a good practice to not have unused parameters in your method calls. There are a handful of exceptions (event handling for one) but for any code that I write, I try to be sure I always use what I'm providing.
To start with, it's not all that important. Consider not fixing what isn't broken.
The preferred approach would be to have several handlers all calling a special method (not an eventhandler).
private void datePicker_DateChanged(object sender, EventArgs e)
{
// tabControl_SelectedIndexChanged(sender, e);
RefreshCurrentTabControl();
}
calling other EventHandler is obviously not good pracice. Becouse if tabControl_SelectedIndexChanged change in time and start depend on sender all code fails or star work unexpedted..
I'll separate same logic in third method like you said.. loadCurrentTab(). You also may consider use some command pattern to handle events -> good way to separate Business Logic from GUI.
For example:
interface ICommand {
void Execute();
}
interface IEventCommand : ICommand {
void Execute(object sender, EventArgs e);
}
class CommandAttribute : Attribute {
...
}
class MyCommand : IEventCommand {
...
}
implement some manager, executor, attach command using reflection, etc...
And then you can attach command like this:
[Command(typeof(MyCommand), new [] {"Click"})]
private Button m_oButton = new Button();
All nessesary parameters are auto-magically ;) passed to command.
Yep that's bad practice, you twiddle with one and break the other in ignorance, classic error would be as simple as ((ComboBox)sender).SomeProperty, because "it can only be called from the Combobox".
Depends on how far you can afford to take the refactoring, but my instant reaction would be at least "RefreshTabControl" to do the work and then get the eventHandlers to call it. If you have to expand upon that, ie Sender Or EventArgs matters, then some form of delegation as suggested, or not as clever but much better than what you have, would be an overload.
e.g
void RefreshTabControl(Combobox argBox, EventArgs e)
and then a cast and null check in the eventhandler, at least that would be a statement of intent.
What you have now is a bug waiting to happen.
Related
I have two classes with the same event handler essentially, but the event handler calls the same method with different jagged List arguments.
public void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
drawMap(e, myTextFileHandler.getMapCellWalls(), myTextFileHandler.getMapCellPositions());
}
public void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
myGameForm.drawMap(e, mapCellWallList, mapCellPositionList);
}
Can i just reuse the pictureBox1_Paint by adding two parameters which are the jagged lists used in drawMap()?
I did try it but then i noticed that when i call pictureBox1_Paint, i do not even give it one parameter, which very much confused me. EG:
private void LevelDesignerForm_Load(object sender, EventArgs e)
{
myGameForm.defineMapArea(this, this.pictureBox1_Paint);
}
What is the best practice way? Because i feel as if i copy and pasted a method almost. Any help appreciated. Thanks
First, you cannot call an event handler defined in a different class directly. Though you can do this by editing the event handler mapping in InitializeComponent something like below, its not good practice.
this.Paint += new System.EventHandler(new class1().pictureBox1_Paint);
Secondly, you cannot change the signature of the event handler. If you observe the above code, you are just giving the name of method. So, you don't have provision to pass the data to it.
However, you can use the Tag property of the components if you really wants to go with this approach. You can store any object (of course only one) into it and in the event hanlder you can typecast to its original type and process.
I feel the best practice is what you have right in hand.
Preceding posts:
Event Signature in .NET — Using a Strong Typed 'Sender'?
In a C# event handler, why must the “sender” parameter be an object?
Microsoft's conventions and guidelines force .NET users to use special pattern for creating, raising and handling events in .NET.
Event design guidelines http://msdn.microsoft.com/en-us/library/ms229011.aspx state that
Citation:
The event-handler signature observes the following conventions :
The return type is Void.
The first parameter is named sender
and is of type Object. This is the
object that raised the event.
The second parameter is named e and
is of type EventArgs or a derived
class of EventArgs.This is the
event-specific data.
The method takes exactly two
parameters.
These conventions tell developers that the (following) shorter and more obvious code is evil:
public delegate void ConnectionEventHandler(Server sender, Connection connection);
public partial class Server
{
protected virtual void OnClientConnected(Connection connection)
{
if (ClientConnected != null) ClientConnected(this, connection);
}
public event ConnectionEventHandler ClientConnected;
}
and the (following) longer and less obvious code is good:
public delegate void ConnectionEventHandler(object sender, ConnectionEventArgs e);
public class ConnectionEventArgs : EventArgs
{
public Connection Connection { get; private set; }
public ConnectionEventArgs(Connection connection)
{
this.Connection = connection;
}
}
public partial class Server
{
protected virtual void OnClientConnected(Connection connection)
{
if (ClientConnected != null) ClientConnected(this, new ConnectionEventArgs(connection));
}
public event ConnectionEventHandler ClientConnected;
}
Though these guidelines not state why is it so important to follow these conventions, making developers act like monkeys who don't know why and what are they doing.
IMHO, Microsoft's event signature conventions for .NET are bad for your code because they cause additional zero-efficiency effort to be spent on coding, coding, coding:
Coding "(MyObject)sender" casts (not speaking about 99% of situations that don't require sender at all)
Coding derived "MyEventArgs" for the data to be passed inside event handler.
Coding dereferences (calling "e.MyData" when the data is required instead of just "data")
It's not that hard to do this effort, but practically speaking what are we loosing when not conforming to Microsoft's conventions, except that people take you as an heretic because your act of confrontation to Microsoft's conventions verges on blasphemy :)
Do you agree?
The problems you will have:
When you add another argument, you
will have to change your event
handler signature.
When a programmer first looks at
your code, your event handlers will
not look like event handlers.
Especially the latter can waste you far more time than writing a 5 line class.
Regarding having a strongly-typed sender, I've often wondered that myself.
Regarding the EventArgs, I'd still recommend you use an intermediate EventArgs class because you may want to add event information in the future which you don't currently foresee. If you've used a specific EventArgs class all along, you can simply change the class itself and the code where it gets fired. If you pass the Connection as per your example, you'd have to refactor every event handler.
Edit
Jim Mischel made a good point in his comments. By making the sender an object, we enable the same event method to potentially be reused to handle a variety of events. For example, let's say that a grid needs to update itself if:
the user clicks a "refresh" button, or
the system detects that a new entry has been loaded from the server.
You could then say something like this:
serverBus.EntryReceived += RefreshNeededHandler;
refreshButton.Click += RefreshNeededHandler;
...
public void RefreshNeededHandler(object sender, EventArgs args)
{
...
}
Of course, in practice, I have pretty much never had any call for this kind of reuse, whereas the first thing I tend to to in many, many cases is cast the sender to the object type that I know it has to be. If I want to reuse handlers like this, I think it would be easy enough to make two handlers that both call the same convenience method. For me, an event handler is conceptually supposed to handle a specific type of event on a particular group of objects. So I am not personally convinced that the object sender approach is the best convention.
However, I can imagine cases where this would be extremely handy, like if you want to log every event that gets fired.
The biggest problem I see in not following the convention is that you're going to confuse developers who are used to handling events in the way that the runtime library does. I won't say that the convention is good or bad, but it's certainly not evil. .NET developers know and understand how to work with events that are written in conformance with Microsoft's guidelines. Creating your own event handling mechanism on top of that may be more efficient at runtime and might even lead to code that you think is cleaner. But it's going to be different and you'll end up with two event handling "standards" in your program.
My position is that it's better to use a single less-than-ideal standard (as long as it's not horribly broken) than to have two competing standards.
I used strongly typed events (instead of object as it saves me having to cast), it really isn't that hard to understand, "oh look they've used a type that isn't an object"
As for eventArgs, you should use this in case the object changes as per #StriplingWarrior answer.
I don't understand why devs would get confused over it?
I'm probably just being neurotic, but I regularly find myself in situations in which I have class that publishes an event, and I find it convenient to subscribe to this event from within the class itself (e.g. in the constructor), rather than only subscribing from external classes.
This sounds reasonable to me, but I can't help the nagging feeling that it's a poor practice, for the simple reason that I'm always faced with the question: "Why not perform the actions that you'd provide in the event handler in the code which fires the event?"
public class Button
{
public Button()
{
this.Click += someHandler; // bad practice?
}
public event EventHandler Click;
public void HandleInput()
{
if (someInputCondition)
{
// Perform necessary actions here rather than
// subscribing in the constructor?
this.Click(this, ...);
}
}
}
Are there any drawbacks to subscribing to your own events?
This sounds reasonable to me, but I can't help the nagging feeling that it's a poor practice, for the simple reason that I'm always faced with the question: "Why not perform the actions that you'd provide in the event handler in the code which fires the event?"
To answer that question, consider partial class scenarios. Suppose you have a base type B. You run an automated tool that decorates B by extending it to derived class D. Your tool generates a partial class so that developers consuming D can further customize it for their own purposes.
In that case, it seems perfectly reasonable that the user-authored side of D would want to sign up to be called when events declared by B or the machine-generated side of D are raised by the machine-generated side of D.
That was the scenario we found ourselves in when designing VSTO many years ago. As it turns out, it was not difficult to do this in C# but it was quite tricky to get it all working in VB. I believe VB has made some tweaks to their event subscription model to make this easier.
That said: if you can avoid this, I would. If you're just making an event for internal subscription that seems like a bad code smell. Partial methods in C# 3 help out greatly here, since they make it easy and low-cost for the machine-generated side to call little notification functions in the user-generated side, without having to go to the trouble of publishing an event.
I see no problem with this. But if you handle the events in the same class you could also override the event method:
protected override void OnClick(Eventargs e)
{
base.OnClick(e);
}
This is more efficient and gives you the power to swallow the event if necessary (simply not calling base.OnClick()).
There's a very exotic problem due to internal optimization when doing this. Due to the optimization adding/removing event handlers is not thread safe. It only applies to events that are used by the declaring type like in your example.
Fortunately this has been changed with 4.0, but if you're on previous version, you could experience this.
The issue is that “someHandler” will change the state of your object. Do you want this state changing before or after any “external” code is run by the event?
It is not clear at what point the state change will be make if you subscribe to the event, however calling it in “HandleInput()” make it a lot clearer when it will be called.
(Also it is more normal to call “HandleInput()”, “OnClick” and make it virtual so sub classes can override it)
After saying the above, normally there is no great harm in subscribing to your own event; in UI classes that represent forms it is very common, otherwise it tend to “surprise” a lot of people that read your code.
If your button class should be the first which receives the click event, you should write your code in the event method, eg.:
protected virtual void OnClick(EventArgs e)
{
//insert your code here
if(this.Click != null)
{
this.Click(this, e);
}
}
but if it's not necessary that your class is the first reciever, you can subscribe to the event normally.
if you take the ordinary System.Windows.Form class as an example,
when you want to handle the Form_Load event (using visual studio designer), it is handled
in the class of the Form itself !
this.Load += new System.EventHandler(this.Form1_Load);
private void Form1_Load(object sender, EventArgs e)
{
}
so i think it is not a problem at all !!.
My class with an event:
public class WindowModel
{
public delegate void WindowChangedHandler(object source, WindowTypeEventArgs e);
public event WindowChangedHandler WindowChanged;
public void GotoWindow(WindowType windowType)
{
this.currentWindow = windowType;
this.WindowChanged.Invoke(this, new WindowTypeEventArgs(windowType));
}
}
Derived event class:
public class WindowTypeEventArgs : EventArgs
{
public readonly WindowType windowType;
public WindowTypeEventArgs(WindowType windowType)
{
this.windowType = windowType;
}
}
Some other class that register it to the event:
private void SetupEvents()
{
this.WindowModel.WindowChanged += this.ChangeWindow;
}
private void ChangeWindow(object sender, WindowTypeEventArgs e)
{
//change window
}
What have I gained from following the .Net convention?
It would make more sense to have a contract like this
public delegate void WindowChangedHandler(WindowType windowType);
public event WindowChangedHandler WindowChanged;
Doing it this way, I don't need to create a new class and is easier to understand.
I am not coding a .Net library. This code is only going to be used in this project. I like conventions but am I right when I say that in this example it does not make sense or have i missunderstood something?
Viewed in isolation, yes, you're correct: the .NET conventional syntax is more verbose and less intuitive, but there are advantages:
Future changes to the information passed by your event do not automatically require changes to every consumer of the event. For example, if you wanted to add an additional piece of information to your event--say, a WindowTitle string--you'll have to modify the signature of every single function that gets attached to that event, regardless of whether or not they use it. With the EventArgs approach, you add the property to the arguments and only alter the functions that need to take advantage to the additional information.
Since .NET 2.0 introduced the EventHandler<TEventArgs> delegate type, you no longer need to define your own event delegates manually. In your example, you would type your event as EventHandler<WindowTypeEventArgs> instead of WindowChangedHandler.
The EventArgs approach makes it easy to pass multiple types of information back to the calling function. If you needed to do this in your alternative example (that passes the event parameter directly), you'd still end up creating your own -tuple class to hold the information.
The impact of the first one is made more evident when you look at the actual pattern for .NET events in creating a protected virtual function that actually does the invoking. For example:
public event EventHandler<WindowTypeEventArgs> WindowChanged;
protected virtual void OnWindowChanged(WindowTypeEventArgs e)
{
var evt = WindowChanged;
if(evt != null) evt(this, e);
}
There are a couple of things I'd like to point out here:
Using the pattern of creating this event-invoking method allows you to avoid null checking throughout your code (an event without any functions attached to it will be null and will throw an exception if you try to invoke it)
This pattern also allows classes that inherit from you to control the order of invocation, allowing them to execute their code explicitly either before or after any outside consumers
This is especially important in multithreaded environments. If you just said if(WindowChanged != null) WindowChanged(this, e);, you would actually run the risk of the WindowChanged event becoming null between the time you check it and the time you call it. This isn't important to do in single-threaded scenarios, but is a great defensive habit to form.
I recognise your confusion! I had the same feeling when I first looked at this too.
The big thing to realise is that it doesn't give you much of an advantage programmatically speaking, but it is a convention that is well known in the framework. As such, there are plenty of tools that expect the void EventName(object sender, EventArgs e) signature. Some IoC containers, for example, can use this signature to auto wire events at construction time.
In short, it looks a bit weird, but it's a convention. Stick with it and the bulb will light up eventually!
You can use your delegate. Nobody will force you. It's just a good pattern for events.
If you use standart Sender-EventArgs pattern you'll be able to use the same ChangeWindow handler for other events too.
Ted Faison in a podcast on event-based software design mentioned that "sender" and "self" objects in .NET, C++ and Java event statements such as:
private void Button_Click(object sender, RoutedEventArgs e)
are a misnomer since e.g. in the above example "sender" is not really the object which produced the event but a proxy, since you wouldn't want to couple your applications that tightly.
Did I understand him incorrectly (since when I debug it, "sender" does indeed seem to be the original object).
Or is it that common event patterns in these languages (e.g. a common click handler) are tightly coupled but they should be more decoupled, e.g. in composite applications.
He also mentioned that e.g. you shouldn't make inherit from EventArgs since it leads to an explosion of classes, one per event, which only transport a few variables. Many times in his opinion, you can just send a string for instance. He mentioned that this opinion is the opposite of what Microsoft Patterns and Practices suggests.
Any thoughts on these areas?
In most cases, sender is the Button (or whatever) that raised the event. There are some occasions when this isn't the case - such as a (perhaps lazy) pass-thru event:
class Foo {
private Bar bar;
public Foo(Bar bar) {
this.bar = bar;
}
public event EventHandler SomeEvent {
add {bar.SomeEvent += value;}
remove {bar.SomeEvent -= value;}
}
//...
}
Here, if we subscribe to foo.SomeEvent, we will actually get back the event originated by the Bar instance - so sender won't be foo. But this is arguably because we've implemented Foo.SomeEvent incorrectly.
To be honest, in most cases you don't need to check sender; the main time this is useful is when a number of controls share a handler. You should generally be able to assume the sender is the instance you subscribed to (for the purposes of reference-equality tests).
Re EventArgs - the standard pattern (when creating a new event-type) would recommend you to inherit from this. I don't recommend deviating from this. A minor reason is that it allows you to use EventHandler<T>, but there are other variance reasons too. Besides - sometimes doing what other people expect is reason enough; people expect an EventArgs derived value.
That said - I have done non-standard events before (in MiscUtil's Push LINQ) - but this was already in a very unusual setup, so it didn't feel out of place.
First - the 'sender' will hold a reference to the button you clicked. If you have multiple buttons all hooked to the same event, this is how you see which one of the buttons you hit (if you're not passing something in the event arguments to read this).
Also I do to some extend agree that writing new eventargs inheriting frmo EventArgs can lead to explosion of classes - so use with causion. I like just raising an EventArgs.Empty and then have the code catching the event explicit querying the object that raised the event for the data. What i mean is - once you catch the event, instead of reading the data from the event arguments you go to the object that raised the event and read those of its properties you are interrested in. This makes it easier to just read what you need, but ofcourse - you could find yourself in a situation where those properties changed between the event raised and you reading the properties.