Click here to Skip to main content
15,909,193 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I created a user control with an event. I do not want to add the following code every time I add a new instance of the control to a form.

C#
Control1.Operate += new MyControl.OperateEventHandler(Control1_Operate)


Instead I would like to simply double-click the control and have the above code added by the IDE to the Designer file. By default the Control1_Load event is assigned in the Designer file. Is it possible to change this?
Posted
Comments
BillWoodruff 5-Nov-11 4:13am    
+5 for this excellent question which taught me a lot.

Until OriginalGriff's Attribute based solution (below), made me want to see exactly what the limits of what could be done with the Attribute based technique were, I had never thought that you could use an Attribute to make a 'user-defined Event' the default code written when a UserControl is placed in a Container and double-clicked at design-time; I had assumed what 'DefaultEvent could 'hard-wire' into design-time behavior were only 'lowest-common-denominator' events, the subset of Events common to all descendants of 'Control.

The last answer/code I posted here demonstrates you can, indeed, auto-generate a user-defined Event; and I'm delighted to learn that ! Perhaps "old news" to OriginalGriff, but new to me :)

thanks, Bill

You need to set an attribute. This sets it to the Click event:
C#
[System.ComponentModel.DefaultEvent("Click")]
public partial class MyUserControl : UserControl
    {
    ...
    }
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 3-Nov-11 20:55pm    
First, my 5 for this correct solution.
Second, please read a note of warning in my solution.
--SA
David J Perez 3-Nov-11 22:01pm    
Thanks for your help!
BillWoodruff 5-Nov-11 1:12am    
+5 for your answer ... well, de rigeur :) Will post a response here that does show that the technique you suggest can actually be extended to do exactly what the OP asked ... for which you should get full credit ! Even if it does cause a slight elevation in blood-pressure for SAK :)
Just a note of warning:

This is so good that System.ComponentModel is not a part standard .NET library (by "standard" I mean standardization under ECMA and ISO). Some .NET libraries are wonderful, some are not so good; and System.ComponentModel is the worse one from what I know.

Take this class System.ComponentModel.DefaultEventAttribute. It requires either immediate or explicit string constant as its argument. This is the worst case from the maintainability standpoint. If the string passes as a parameter is misspelled, a compiler cannot checkup anything and issue a single warning, but the behavior of the component under Designer will be modified. Some constructor of attribute classes require statically known type (hence, passed through typeof); it does not allow to provide any type constraint, but at least the compiler can check up if this is a really existing type. This is bad, too, but not as bad as a string constant.

With System.ComponentModel, such rotten technique is used all the time. I mean it: this is not a problem of Reflection, where the meta-data can be extracted from a type without using any string constants like member names (which is also possible), this is a problem of System.ComponentModel. There are fundamental problems related to limitations of attributes and System.Type (not quite a fully-fledged meta-class), but nevertheless most .NET libraries are free from System.ComponentModel.

I also explain some of related problems in my article Human-readable Enumeration Meta-data[^].

I would recommend anyone not to do much effort struggling with System.ComponentModel and Forms Design-time behavior. Microsoft already provided two new UI models; and who knows? may be life time expectancy of Forms and System.ComponentModel does not deserve wasting our lives on working to much in this direction? Our investment in our working time may never pay off…

—SA
 
Share this answer
 
v2
Comments
David J Perez 3-Nov-11 22:00pm    
Your warning is a bit over my head but I am moved by your passion.
Sergey Alexandrovich Kryukov 3-Nov-11 23:12pm    
Thank you, David. This warning is important enough and clear enough. As you already got a solution from Griff, you should have understood what could happen if you misspell the string like "Click" in the code sample. Do you see that in this case 1) a compiler will not give any warning, 2) the effect of attribute will disappear (at best)?
--SA
Sergey Alexandrovich Kryukov 3-Nov-11 23:12pm    
If just this is understood, I hope it's enough to accept this advice formally (green button) :-) - thanks.
--SA
BillWoodruff 3-Nov-11 23:33pm    
@SAK: An interesting and educational critique of ComponentModel ! And interesting to note that even though the 'default' Forms and UserControls created by adding these to a WinForms project insert 'Using' statements that invoke ComponentModel, these can, unless you're using Attributes or special custom Designers, or whatever, be removed with no side-effects (caveat: verified only in .NET 4.0 Client FrameWork).

Would be interesting to know if any of the current state-of-the-art tools like JustCode or ReSharper do any Attribute analysis or checking.
Sergey Alexandrovich Kryukov 4-Nov-11 15:39pm    
Thank you, Bill.
Attribute analysis and Reflection is not evil, this is good stuff. Evil is using string constants. More fundamentally, the problem is the limitations of attribute parameters, but this cannot be resolved easily because of their static nature. Development of fine-grained type constraint could be a great help, but .NET turned out of this way when inheriting from Delphi which had decent meta-classes.
--SA
OriginalGriff's answer, and SAK's eloquent critique of System.ComponentModel, are a feast for the intellect, and may well give you all the tools you need to achieve your solution.

But, I'm going to go, recklessly, 'out on a limb' here, and suggest a very different approach to this.

And, you'll forgive me, I hope, if I do this via Socratic method ... an 'experiment' for me, as well as you, perhaps ... since it would be interesting to me to know if what (I hope) I am implying by experimentation "resonates" with you.

Let me just ask to you do a simple experiment:

1. create a WinForms project, add a UserControl template to the project, insert one TextBox into the UserControl template, 'textBox1.' Leave the Text of textBox1 'blank.'

2. in the Load event of that UserControl put this one line of code:
textBox1.Text = "uc loaded";
3. Build the project.

4. at design-time drag-drop an instance of the compiled UserControl onto the surface of the Form.

5. observe what appears in textBox1 of the UserControl.

6. delete the design-time placed UserControl from the Form.

7. put a button on the Form and set its click handler to:
C#
private void button1_Click(object sender, EventArgs e)
{
    UserControl1 uc1 = new UserControl1();
    this.Controls.Add(uc1);
}
8. once again observe what appears in the textBox1 of the UserControl.

9. Now: alter the code in the UserControl's Load event:
textBox1.Text = "uc loaded : " + this.Parent.Name;
10. Now once again build the Project and drag-drop an instance of the UserControl onto the Form surface: observe what's in textBox1.

11. Now delete the drag-dropped UserControl from the Form and run the project, and click on button1 in the Form that creates a new UserControl in code:

12. Observe the contents of textBox1 in the UserControl

Discussion:

0. note that the experiment described above does NOT require a reference to System.ComponentModel for either Form or UserControl.

1. why use a cannon to shoot a horse-fly ? i.e., why get involved with Attributes and System.ComponentModel ... if there's a simpler way ?

2. You now know (I hope) that whether a UserControl is drag-dropped on a Form at design-time, or created at run-time, its Load event is fired, and ... in that Load event ... access is available to the object (in this case a Form) that is creating it.

3. I'll assume that the technique required to publish/expose some method or whatever on a Form ... so it's available from an instance of the Form from outside the scope of the Form definition ... is obvious to you.

I'd be very interested to know if what is suggested here seems like a basis for a solution to the question you ask. And, I'm ready to drink the hemlock if the verdict requires it :)

experimentally yours, Bill
 
Share this answer
 
v2
Comments
David J Perez 4-Nov-11 14:59pm    
I've gone through your procedure and I did learn something about the Load event that may prove useful in the future but I don't see how it could help in this situation. This solution requires a reference to an event handler and the only way I, a newbie, know to do this is by writing code. Either I do it or I add the [attribute] and have the IDE/Compiler do it. It cannot be programmed through the Load event but I wish it could be.
BillWoodruff 5-Nov-11 1:09am    
Hi David, Well, glad you got something from this 'spelunk' into the flickering shadows on the walls of the cave :) I will leave this answer up here, even though I think it's too far a digression from your original question to be that relevant .... it just might be interesting to someone.

Meanwhile I have two other responses that I do think you may find specifically on-topic, and of interest, and will post those, also.

... mmmm ... hemlock ... tasty ! :)

best, Bill
< This is really an extended comment, but, since it includes code, I think it more appropriate posted as 'solution.' >

Please vote for OriginalGriff's answer above, since this reply here simply extends OG's prescient suggestion to meet the precise requirements of the OP.

WinForms Project: one Form, 'Form1,' one UserControl, 'UserControl1,' one TextBox inside UserControl1, 'textBox1'

1. make sure you have a reference (or skip to step #2a) in the UserControl library-reference header to:
using System.ComponentModel;
2. adorn the UserControl definition with this attribute: like so:
C#
[DefaultEvent("OperateEvent")]
public partial class UserControl1 : UserControl
{
2.a. okay: if you just hate typing the word 'using:' use this for the Attribute, as OG's example shows:
[System.ComponentModel.DefaultEvent("OperateEvent")]
3. Define an Event in the UserControl's code:
C#
public delegate void OperateEventHandler(Object sender, EventArgs e);

public event OperateEventHandler OperateEvent;

public void Operate(object sender, EventArgs e)
{
    textBox1.Text = "Operate: called from " + sender.ToString();
}
4. Define the Load event of UserControl1:
C#
private void UserControl1_Load(object sender, EventArgs e)
{
    textBox1.Text = "uc loaded : " + this.Parent.Name;
    this.OperateEvent += new OperateEventHandler(Operate);
}
5. And now ... the moment of truth ... build the Project: at design-time drag and drop a UserControl1 from the ToolBox onto Form1's surface, and then double-click on it. Observe the code generated in Form1. Repeat until satiated.

~

There are other interesting methods for such "indirect auto-event-hooking" you can use when creating custom-controls at run-time, as I hope was implied (even if unsatisfactorily 'rendered') by my first answer on this thread.

 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900