How to select an arbitrary area on a form using sender / what EventHandler?

R

raylopez99

I have a form, Form6, that has a bunch of buttons overlaid on it. I
want to be able to click on any arbitrary area of the form, and if
that area of the form is overlaid by a button, I want to change the
color of the button to Coral, and show a MessageBox with the button
name.

So far, I've tried the below event handlers, and the only one that has
worked is of course the named button event click, for a particular
named button (button3 below), but, I don't want to set up such click
events for each button, since the form Form6 has an arbitrary number
of buttons and/or a large number of buttons on it.

Any way to do this in C#?

Thanks

RL

//////////

private void Form6_DoubleClick(object sender, EventArgs e)
{
//double clicking on form will cause this event to
trigger, which checks to see if a particular button clicked
if (sender.GetType() ==
typeof(System.Windows.Forms.Button))
{
Button currentButton = (Button)sender;
currentButton.BackColor = Color.Coral;
MessageBox.Show("Button doubleclicked is: " +
currentButton.Text);
}
}

private void Form6_MouseDoubleClick(object sender,
MouseEventArgs e)
{
//double clicking on form will cause this event to
trigger, which checks to see if a particular button clicked
if (sender.GetType() ==
typeof(System.Windows.Forms.Button))
{
Button currentButton = (Button)sender;
currentButton.BackColor = Color.Coral;
MessageBox.Show("Button doubleclicked is: " +
currentButton.Text);
}
}

private void Form6_MouseMove(object sender, MouseEventArgs e)
{
if (sender.GetType() ==
typeof(System.Windows.Forms.Button))
{
Button currentButton = (Button)sender;
currentButton.BackColor = Color.Coral;
MessageBox.Show("Button MouseMove: " +
currentButton.Text);
}

}

private void button3_Click(object sender, EventArgs e) //only
this event handler works
{
if (sender.GetType() ==
typeof(System.Windows.Forms.Button))
{
Button currentButton = (Button)sender;
currentButton.BackColor = Color.Coral;
MessageBox.Show("Button #3!: " + currentButton.Text);
}

}

private void Form6_MouseDown(object sender, MouseEventArgs e)
{
if (sender.GetType() ==
typeof(System.Windows.Forms.Button))
{
Button currentButton = (Button)sender;
currentButton.BackColor = Color.Coral;
MessageBox.Show("Button MouseDown: " +
currentButton.Text);
}
}
 
F

Family Tree Mike

This code in your form should do what you want, if I understand correctly.

public Form1()
{
InitializeComponent();

foreach (Control c in Controls)
{
if (c is Button)
{
Button b = (Button)c;
b.Click += new EventHandler(b_Click);
}
}
}

void b_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
Color old = b.ForeColor;
b.ForeColor = Color.Coral;
MessageBox.Show(b.Name);
b.ForeColor = old;
}
 
R

raylopez99

This code in your form should do what you want, if I understand correctly..

Yes, thanks FTM! It worked fine. Just to complicate things and as a
teaching exercise to show for me how delegates work, I added a helper
function that is based on a user defined delegate. The helper
function shows a MessageBox with the button's name, when the button is
clicked. I used two different delegate/event based variables, one
being static, the other being non-static, to fire this helper
function.

It's interesting that you cannot define easily name a delegate Click
since there is a Click delegate (namely, the standard button click
event) already named in .NET, so it's forbidden to do so (compiler
error) unless you want to overload Click, which I don't want to touch,
so I used another delegate name. The location of the 'firing' of the
non-static and static-versions of the event is the same, but the
'registration' of the event is different for non-static (must be
declared once) versus static (must be declared inside of the _Click
function).

Below is the code.

RL

// 7/26/2008
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace MDIForms
{

public partial class Form6 : Form
{
public delegate void ShowNameButEventHandler(object source,
EventArgs e);

//instance class version
public class ButtonHelper
{
public event ShowNameButEventHandler ShowNameBut;
public void OnShowNameBut(Button be, EventArgs e)
{
if (ShowNameBut != null) ShowNameBut(be,
EventArgs.Empty);
}

}

//static class version
public static class staticButtonHelper
{
public static event ShowNameButEventHandler
staticShowNameBut;
public static void staticOnShowNameBut(Button be,
EventArgs e)
{
if (staticShowNameBut != null) staticShowNameBut(be,
EventArgs.Empty);
}
}

Button[] buttons; //Button must be declared here to have
proper scope

/*
// *&* public event EventHandler Click; //not needed since
system has one predefined nongeneric EventHandler delegate called
“Click” already (button click), hence get compiler warning:
'MDIForms.Form6' already contains a definition for 'b_Click'
*/

public Form6()
{
InitializeComponent();
buttons = new Button[] { this.button1,
this.button2,this.button3,this.button4,this.button5,this.button6,this.button7,this.button8,this.button9 };
//buttons 1-9 created using designer wizard prior to runtime

ButtonHelper buttonHelper = new ButtonHelper();

staticButtonHelper.staticShowNameBut += new
ShowNameButEventHandler(buttonHelper_ShowNameBut);

/*
//registration (old-style format); placing registration here is
mandiatory for static version // to prevent more than once
instantiation (compare with non-static version)
*/

foreach (Control c in Controls) //note convention
{
if (c is Button)
{
Button b = (Button)c;
//note convention "Click" is Delegate for signature function "_Click"

b.Click += b_Click; //new style registration;
// b.Click += new EventHandler(b_Click); //oldstyle format also
works

/*
// staticButtonHelper.staticShowNameBut += new
ShowNameButEventHandler(buttonHelper_ShowNameBut); //register,(modern
style) but don't register here--get nine instances!
// buttonHelper.ShowNameBut +=new
ShowNameButEventHandler(buttonHelper_ShowNameBut); //works but should
not be registered here...you get nine popup Message boxes when form
constructed, not what you want
*/

// buttonHelper.OnShowNameBut(b,EventArgs.Empty);
//works but should not be fired here…get up to nine instances of
MessageBox

}
}

}


void b_Click(object sender, EventArgs e) {
Button b = (Button)sender;
Color old = b.BackColor;
b.BackColor = Color.Coral;

// NON-STATIC VERSION OF EVENT (works fine)
// ButtonHelper buttonHelper1 = new ButtonHelper(); //
create instances of ButtonHelper for non-static version of event
delegate
// buttonHelper1.ShowNameBut += new
ShowNameButEventHandler(buttonHelper_ShowNameBut); //register the non-
static public event
// buttonHelper1.OnShowNameBut(b, EventArgs.Empty); //fire
here, non-static instance version (works)

//STATIC VERSION OF EVENT (works fine)
// staticButtonHelper.staticShowNameBut += buttonHelper_ShowNameBut;
//WRONG PLACE TO register static version (gives up to nine
instantiations, everytime the loop is traversed another added)


staticButtonHelper.staticOnShowNameBut(b, EventArgs.Empty);
//fire here, static version;

/*
// both static and non-satic versions of ButtonHelper fired from
inside b_Click, which is automatically fired when buttons are clicked
(depends on button click, see *&* above)
*/

}

//static member function used by delegate/events (same for both static
and non-static delegate/events
static void buttonHelper_ShowNameBut(object sender, EventArgs
e)
{
Button b = (Button)sender;
MessageBox.Show(b.Name + "!");
}

} //end bracket, form 6
} //end bracket, namespace
 
R

raylopez99

Yes, thanks FTM!  It worked fine.  Just to complicate things and as a
teaching exercise to show for me how delegates work, I added a helper
function that is based on a user defined delegate.  The helper
function shows a MessageBox with the button's name, when the button is
clicked.  I used two different delegate/event based variables, one
being static, the other being non-static, to fire this helper
function.


UPDATE: the non-static version works much better. The static version
has a 'bug' that results from the fact the 'static' class is not
garbage collected when the window closes (this happens to be a sub-
form or child window). Then, when you reopen the child window again,
the non-static class has delegate instances that necessitate in
multiple firings. Everytime you close and reopen the window,more of
these delegates accumulate, to the point where if you open and close
the window 10 times, you'll have to click through 10 MessageBoxes for
each time you click on a button.

But the non-static version doesn't have this problem, since the
instance class is garbage collected when the window is closed.

RL
 
R

raylopez99

But the non-static version doesn't have this problem, since the
instance class is garbage collected when the window is closed.

RL

The static version apparently also has to be garbage collected, and is
not being done so properly, refer to some other threads here,
".The object isn't static, it's only the reference to the object that
is static. The object is allocated on the heap just like any other
object, and if you remove the reference from the static variable (e.g.
setting it to null), the object can be garbage collected."

RL
 
R

raylopez99

The static version apparently also has to be garbage collected, and is
not being done so properly, refer to some other threads here,
".The object isn't static, it's only the reference to the object that
is static. The object is allocated on the heap just like any other
object, and if you remove the reference from the static variable (e.g.
setting it to null), the object can be garbage collected."

RL

Here is how I fixed the static version bug, without having to resort
to Dispose, which I hate to fool with.

Simply 'unsubscribe' the event when the subform / child form, Form 6,
closes, like so:

private void Form6_FormClosing(object sender,
FormClosingEventArgs e)
{
staticButtonHelper.staticShowNameBut -=
buttonHelper_ShowNameBut; //dispose of this (to prevent multiple
instances for static version) //works!

}

Now, when you reopen the form, you will only have one static Event/
Event hander/ delegate, and the program will work properly.

This is done automatically in the non-static version, when the
instantiated object, variable buttonHelper1, goes out of scope, but
for the static version you have to manually get rid of the variable as
per the above.

RL
 

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