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.
Related
My first post, apologies if this has been answered already - I have searched and searched but have not found any specifics on using Custom EventArgs with existing SystemEvents.
I am trying to take advantage of the SystemEvents.PowerModeChanged type events but would like to use my own Custom EventArgs instead of the standard PowerModeChangedEventArgs. My approach was to create a class called CustomPowerModeChangedEventArgs which inherits from PowerModeChangedEventArgs and use these instead but I don't know how to tell the PowerModeChangedEventHandler to use these new CustomEvent args. My code is as follows:
//Define the custom args which inherit from the PowerModeChangedEventArgs
public class CustomPowerModeChangedEventArgs : PowerModeChangedEventArgs
{
public string batterylevel { get; set; }
}
//event raising method with CustomArgs instead of the PowerModeChangedEventArgs
protected virtual void PowerModeChanged(object source, CustomPowerModeChangedEventArgs e)
{
}
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(PowerModeChanged);
The problem is with the PowerModeEventChangedHandler not accepting the method PowerModeChanged with the CustomArgs. Had it been a generic eventhandler I could define the args like...
public event EventHandler<CustomPowerModeChangedEventArgs> PowerModeCHanged;
...but I can't fathom how to achieve similar with a non generic event handler. I have a suspicion that it might be possible to send the new custom args to the handler using lambda expressions but I'm really not sure about this - maybe I need to define a whole new EventChangedHandler? Any advice would be greatly appreciated.
No, you don't get to decide what parameters the event handler has. Bear in mind that there's already code in the system which is going to call your event handler... how would you expect it to construct an instance of your CustomPowerModeChangedEventArgs?
If the event had been declared using EventHandler<T>, that still wouldn't have helped you - the code calling the event handler has already been written, and it's going to pass in a PowerModeChangedEventArgs that it constructs, not an instance of your type.
Now you could declare your own event using your custom event-args, and then hook into the SystemEvents so that you raise your own event (with an instance of your own event-args, however you decide to construct that) when the system event is raised... but you shouldn't expect to be able to add an event handler which requires information the event raiser (in this case the system) isn't aware of.
This is probably a REALLY dumb question, but on the upside I don't think anyone's asked it here before(?)
The default number of parameters in all the button_clicked subscriber methods is two:
(object sender, RoutedEventArgs e)
I recently read that the arguments for the event are defined within the delegate. Now is this just one delegate for each button_clicked event? Or does each button have it's own separate delegate? I'm not explaining myself very well here...
Say I want to pass in three arguments into a single subscriber method instead of the above TWO, I've just had some simple code auto-generated for me after double clicking my button in designer view. Where is the class that that method subscribes to? Is there a way I can edit it's delegate and add in another parameter?
The reason I'm asking this WAS that I thought there could be a way to pass a variable to another class - into it's subscriber method. Unfortunately that subscriber method only takes two arguments. So I'm now looking for ways to easily pass in my variable, and this was a 'back-of-the-mind' sort of solution.
You guys are waaaayy overthinking this :). Simply use a lamda and you can redefine any delegate however you want:
theButton.Click += (x, y) => myHandler(someRandomParam1, someRandomParam2, someRandomParam3, someRandomParam4, ... someRandomParam73);
It's that simple.
You can set the Tag parameter of the button and then retrieve it in the handler.
If the button is defined in XAML:
If the button is defined in code:
var button = new Button() {Tag = "Hi"};
Then in the event handler:
public void Click(object sender, RoutedEventArgs e)
{
// this will give you the string "Hi"
string hi = (string)((Button)sender).Tag;
}
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.
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.
I know they have something to do with delegates. I've tried but I still don't comprehend how to use those either. I know a little about event handlers but what I really want to know is how I can use plain old eventargs that are part of most methods. example below
void Page_Load(object sender, EventArgs e)
{
myText.Value = "Hello World!";
}
Thanks for your time & consideration, I am just trying to be the best coder I can be.
Mike
EventArgs classes are used as data carriers when raising events. They typically contain information that is related to the event being raised.
Many events use the EventArgs class, which contains no particular information. This class also serves as the base class for all other EventArgs classes. One example of a more specific EventArgs class is the TreeNodeEventArgs class, that is used by a number of events, and that contains information about which TreeNode that the event is related to.
In some cases, EventArgs classes can be designed so that they allow event handlers to communicate data back to the source that raised the event, an example of that is the CancelEventArgs class.
The base EventArgs class is an emtpy class that you can't use directly.
However, there are many derived EventArgs classes that provide data about an event.
For example, the KeyPress event gives a KeyPressEventArgs which tells you which key was pressed.
If you get an event handler where the e parameter is an inherited EventArgs, you can use the properties on the inherited EventArgs object to find out more about the event.
Plain old EventArgs are not really that useful, however types that derive from EventArgs are much more useful since you can define other members to carry strongly-typed data.
A good example of this is the GridViewEditEventArgs that are passed by a GridView inherit from EventArgs but extend it to provide NewEditIndex and Cancel properties.