This questions is about the case where renaming a method causes the forms designer to stop working. Although I have covered (all that I can think of) how events works in general.
What happened?
What you experience is an artifact of the forms designer.
Sure, you can have any method name you want, the matter is the forms designer is binding those methods to events behind the scenes, if you change the method name after the forms designer has linked it to the event it will no longer work (it can't find the method).
Giving proper names to your event handlers
In Visual Studio, look at the properties of the object you want to bind an event to, and then select events (on the top of the panel):
There you will see a list the available events and you will be able to bind an existing method or type the name for a new one:
If I have already screwed, how do I fix it?
If your designer is not appearing because of this you will have to edit the code file that is generated by the designer. The file generated by the designer has the name of the form followed by .Designer.cs
(for example: Form1.Designer.cs
), you can find it with your solution explorer:
Note: You may have to expand the sub-tree created on your form to reveal the file.
There you will find a line that looks something like this:
this.button1.Click += new System.EventHandler(this.button1_Click);
And Visual Studio will tell you that button1_Click
is not defined. You can edit there the name of the method to the new name, or remove the line to have the designer work again, and bind a new method.
Renaming an existing method without the hassle
You can summon the Rename dialog. This can be done by several ways:
- From the Menus:
Edit
-> Refactor
-> Rename
- By contextual Menu on the name of the Method:
Refactor
-> Rename
- Put the cursor on the Method name and type
Alt + Shift + F10
and then select Rename
- Put the cursor on the Method name and press
F2
Note: You can customise your Visual Studio, the above menus and keyboard shortcuts may be changed.
The Rename dialog looks like this:
There you can type a new name for the method, and by doing so any reference or call to that method withing the loaded projects will be changed too. That includes the code generated by the Forms Designer.
Binding an event handler by hand
All that the forms designer does is present a UI that facilitates editing the form and write code on your behalf. Don't let it fool you into thinking that you can't write code yourself.
In fact, you can create your own methods and even bind them to the events of your Form. I have been saying "bind" because it is easier to understand at this level, although the accepted lingo is subscribe. So what we are going to do, is create a button and subscribe to its Click
event.
First let's take a look at the class of your form, it looks something like this:
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}
Notice it says partial
, that means that there could be more code for this class in another file, in fact that is the file Form1.Designer.cs
where the forms designer has been adding code.
Second notice it calls a method InitializeComponent
inside the constructor of the form. This method has been created by the forms designer and it takes responsibility of initializing all the controls and components you have added using the forms designer (hence the name of the method).
Now, let's say we want to add a button without the forms designer we can do it like this:
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Button myButton;
public Form1()
{
InitializeComponent();
// Create a new Button
myButton = new Button();
// Set the properties of the Button
myButton.Location = new System.Drawing.Point(50, 12);
myButton.Size = new System.Drawing.Size(100, 23);
myButton.Text = "My Button";
// Add the Button to the form
this.Controls.Add(myButton);
}
}
}
We have created a private field named myButton
of type Button
that will hold the new button. Then inside the constructor we add some new lines to create a new Button
and assign it to myButton
and give it position (Location
), Size
and Text
. And finally we have added the newly created button to the Controls
of the form.
Now we want to add an event handler for the Click event on this new button. Remember that this button is not in the forms designer, we we are going to have to do it "by hand".
In order to do so, add the new method (you can named whatever you want):
private void WhenClick(object sender, System.EventArgs e)
{
/* Code */
}
And then add it as an event handler for the Click event of the button (inside the constructor):
// Add an event handler
myButton.Click += new System.EventHandler(WhenClick);
Notice we are not calling WhenClick
. instead we are making a reference to it.
Then we are creating a new Delegate
of type System.EventHandler
that will wrap the reference to the method WhenClick
. I suggest to learn about Using Delegates.
I repeat: we are not calling WhenClick
. If we were to call WhenClick
we would do something like this: WhenClick(param1, param2)
. Please note that this is not what we are doing here, we haven't added parenthesis (/*...*/)
after the method name, so we are not doing a method call.
You can also use some syntactic sugar to make all this easier:
public Form1()
{
InitializeComponent();
// Create a new Button and set its properties
myButton = new Button()
{
Location = new System.Drawing.Point(50, 12),
Size = new System.Drawing.Size(100, 23),
Text = "My Button"
};
// Add the Button to the form
this.Controls.Add(myButton);
// Add an event handler (the compiler infers the delegate type)
myButton.Click += WhenClick;
}
You can even make the event handler an anonymous method:
// Add an event handler (the compiler infers the delegate type)
myButton.Click += (sender, e) =>
{
/* code */
};
What you see here is a C# Lambda expression (more info at MSDN Lambda expressions). Get used to these syntax, because you will see them more and more often.
Understanding events
You have already seen code like this:
button1.Click += button1_Click;
As I told you we are passing a delegate object that has a reference to button1_Click
. But that's not all that happens here... we are also giving it to Click
.
Let's recapitulate and see how delegates behave. You can think about a delegate like an object that holds a method, or a pointer to a function if you prefer.
To understand this, I'll present some examples you can run as console applications. The first one shows that you can change the method that a delegate points to during runtime:
// Console Application Example #1 ;)
static void Main()
{
Func<int, int> myfunc = null;
myfunc = Add2;
Console.WriteLine(myfunc(7)); // This prints 9
myfunc = MultBy2;
Console.WriteLine(myfunc(7)); // This prints 14
}
static int Add2(int x)
{
// This method adds 2 to its input
return x + 2;
}
static int MultBy2(int x)
{
// This method multiplies its input by 2
return x * 2;
}
Notice myfunc
is typed as Func<int, int>
this is a generic delegate type that takes an int
and returns an int
.
Also notice that when I say myfunc = Add2;
, it is not calling Add2
(there are no parenthesis there), it is passing a reference of the method itself. the same is true for myfunc = MultBy2;
: it is not calling MultBy2
, we are passing it.
Using anonymous methods via lambda expressions you can write equivalent code is less lines:
// Console Application Example #1 ;)
static void Main()
{
Func<int, int> myfunc = null;
// This anonymous method adds 2 to its input
myfunc = x => x + 2;
Console.WriteLine(myfunc(7)); // This prints 9
// This anonymous method multiplies its input by 2
myfunc = x => x * 2;
Console.WriteLine(myfunc(7)); // This prints 14
}
Notice that we have two anonymous methods here: x => x + 2
and x => x * 2
. The first one (x => x + 2
) is equivalent to the method Add2
we had before, and the second one (x => x * 2
) is equivalent to the method MultBy2
we had before.
In this example I want you to see that the same delegate can point to different methods along the time. This is accomplished by having a variable that points to the methods!
For the second example, I'll present the "callback" pattern. That is a common pattern in which you pass a delegate as a "callback", that is: something that will be called "back to you" from the code you are calling:
// Console Application Example #2 ;)
static void Main()
{
Func<int, bool> filter = IsPair;
// An array with numbers
var array = new int[]{1, 2, 3, 4, 5, 8, 9, 11, 45, 99};
PrintFiltered(array, filter);
}
static bool IsPair(int x)
{
// True for pair numbers
return x % 2 == 0;
}
static void PrintFiltered(int[] array, Func<int, bool> filter)
{
if (array == null) throw new ArgumentNullException("array");
if (filter== n