using a delegate in a user control to pass click events to a parent form

T

Todd Schinell

Back in July, Jeffery Tan posted this:

http://groups.google.com/groups?hl=...-8&[email protected]

In response as to how to get click events from a user control to
invoke a method in the parent form.

This code doesn't seem to work for me, I've tried it a number of times
with very simple test cases (A user control with a single button and a
parent form with a single text box) and it always raises the unhandled
exception "Object reference not set to instance of object" at the line
"pointer.DynamicInvoke(null);" in usercontrol.cs

Does anyone have any solutions to this that definitely work, or can
tell me what's wrong with the posting above?

Maybe this is a very basic thing I'm just not getting. Thanks in
advance for your help.

___
/<>/>/>
SkiTag Inc.
 
E

Eric Cadwell

The UserControl was not initialized in Form1. You needed to create a new
instance of the control by calling the constructor that takes the delegate
to be invoked.

userControl11 = new UserControl11(pointer);

This is the opposite of what I'd expect that you to be looking for.
Convention would dictate that the event be defined in the control and the
form would then subscribe to that event and provide a handler for it. Touch
back if you want a code sample of that.


Here's the new code for Form1:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace d
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
private test.UserControl1 userControl11;
private System.ComponentModel.Container components = null;
public delegate void delegatecall();
private event delegatecall pointer;
public void cmdOkay_Click()
{
label1.Text ="parent method called";
}
public Form1()
{
pointer+=new delegatecall(this.cmdOkay_Click );
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
} base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.userControl11 = new test.UserControl1(pointer);
this.SuspendLayout();
//
// label1
//
this.label1.Location = new System.Drawing.Point(96, 40);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(96, 64);
this.label1.TabIndex = 0;
this.label1.Text = "label1";
//
// userControl11
//
this.userControl11.BackColor = System.Drawing.SystemColors.ActiveCaption;
this.userControl11.Location = new System.Drawing.Point(48, 120);
this.userControl11.Name = "userControl11";
this.userControl11.Size = new System.Drawing.Size(150, 72);
this.userControl11.TabIndex = 1;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(296, 238);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.userControl11,
this.label1});
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}
}

HTH,
Eric Cadwell
http://www.origincontrols.com
 
T

Todd Schinell

Thanks Eric, that was precisely it. It works now (!!!)
The sample mentioned below of the conventional solution would be
appreciated, as I will be using this over and over in my app. It
seemed unusual to me too.
Thanks again..
___
/<>/>/>
 
E

Eric Cadwell

I created two samples. In both samples, the UserControl code is complete,
but the Form code only shows the form's constructor and the event handler.
The first sample simply connects an eventhandler to the inherent Click event
of the UserControl. The second sample creates a custom event that allows you
to pass data back to the form.

1. Since UserControl exposes a public Click event you can just add a handler
for it. To just catch the click event of the UserControl requires no custom
code in the UserControl itself and a lot less code in the form to respond to
it.

Form1.cs (only the significant parts of the code):

public Form1()
{
InitializeComponent();
this.userControl11.Click += new
System.EventHandler(this.userControl11_Click);
}
private void userControl11_Click(object sender, System.EventArgs e)
{
label1.Text = "event raised to parent.";
}


UserControl1.cs (all of the code)

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
namespace test
{
public class UserControl1 : System.Windows.Forms.UserControl
{
private System.ComponentModel.Container components = null;

public UserControl1()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
} base.Dispose( disposing );
}
#region Component Designer generated code
private void InitializeComponent()
{
this.SuspendLayout();
//
// UserControl1
//
this.BackColor = System.Drawing.SystemColors.ActiveCaption;
this.Name = "UserControl1";
this.Size = new System.Drawing.Size(152, 150);
this.ResumeLayout(false);
}
#endregion
}
}



2. In this sample you see the creation of a custom event that returns a
custom EventArgs class. This is more work, but you'll need to do this for
more complex events when you want to pass data to the listener of the event.
By clicking the button inside the UserControl it raises the custom event to
the form (if registered).

Form1.cs (only the significant parts of the code):

public Form1()
{
InitializeComponent();
userControl11.CustomClick += new
test.CustomClickHandler(userControl11_CustomClick);
}
private void userControl11_CustomClick(object sender,
test.CustomClickEventArgs e)
{
label1.Text = e.CursorLocation.ToString();
}



UserControl1.cs (all of the code)

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
namespace test
{

public delegate void CustomClickHandler(object sender, CustomClickEventArgs
e);

public class CustomClickEventArgs : EventArgs
{
Point cursorLocation;

public CustomClickEventArgs(Point CursorLocation)
{
cursorLocation = CursorLocation;
}
public Point CursorLocation
{
get { return cursorLocation; }
}
}


public class UserControl1 : System.Windows.Forms.UserControl
{
private System.Windows.Forms.Button button1;
private System.ComponentModel.Container components = null;
public event CustomClickHandler CustomClick;

public UserControl1()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
} base.Dispose( disposing );
}
#region Component Designer generated code
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.BackColor = System.Drawing.SystemColors.Control;
this.button1.Location = new System.Drawing.Point(8, 8);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(136, 23);
this.button1.TabIndex = 0;
this.button1.Text = "fire custom event";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// UserControl1
//
this.BackColor = System.Drawing.SystemColors.ActiveCaption;
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.button1});
this.Name = "UserControl1";
this.Size = new System.Drawing.Size(152, 150);
this.ResumeLayout(false);
}
#endregion
private void button1_Click(object sender, System.EventArgs e)
{
if (CustomClick != null)
CustomClick(this, new CustomClickEventArgs(Cursor.Position));
}
}
}

HTH,
Eric Cadwell
http://www.origincontrols.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top