Writing custom event handler for built-in Click event

And can't seem to get around some restrictions

Page 1 of 1

3 Replies - 10314 Views - Last Post: 28 September 2008 - 09:58 AM Rate Topic: -----

#1 vertizor  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 9
  • Joined: 27-September 08

Writing custom event handler for built-in Click event

Posted 27 September 2008 - 09:39 PM

I'm quite new at C# - but I have read all the event-specific material I could get my hands on, so the ideas for this are somewhat cobbled together.

In a nutshell -

theGame[i][j].Click += clicker.buttonclickHandler(theGame, new ClickArgs(i, j))



the above line is giving me fits. Some additional info ... theGame is an array of buttons, the size of which is set at run time. What I am looking to do, is to have an event handler which can access elements of this array whenever one of the buttons is pressed, Hiding or Showing them.

As I understand it, the line performs a subscription ... so that clicker is now listening for the Click event from the specific button. This process is then repeated for each button in a for loop. The error I get is that the return type of my buttonclickHandler, which is void, is incorrect (should be System.EventHandler). However, System.EventHandler can't take custom arguments ... and I [believe] I need custom arguments in order to record which button was pressed.

I can post the full source if necessary, but it seems to me it's a bit long. Oh ... clicker is an instance of a the class that contains the buttonclickHandler method. And I do have the delegate setup in what I believe to be the correct way ...

Some things I've tried -
1) Well, I tried changing the return type to System.EventHandler ... however, this gave an error when I tried to pass ClickArgs instead of the generic EventArgs
2) I tried using new <Class Name>.buttonclickHandler( ...) ... this gave me an error that I was trying to use buttonclickHandler as a type instead of a method. I still think I may need something like this, as having the same instance subscribed to all of the buttons click events doesn't seem right to me.
3) I tried having the handler in the same class as the above line of code. This didn't seem to help, besides which the above is in a Form class that I didn't want to instantiate again ... perhaps it should be better partitioned.
4) At one time, through some manipulations, I got it to sort of work ... the event handler triggered, but apparently only when the button was created. After, when I clicked buttons, the handler did not trigger.

On second thought, here is most of my source ... some is in other files, and doesn't seem germane to the specific issue

public delegate void ClickDelegate(object sender, ClickArgs e);
	public partial class gameForm : Form
	{
		//Padding is size of a form beyond what is needed for the buttons
		//Offset is the position on the screen
		const int GAME_FORM_PADDING_X = 40;
		const int GAME_FORM_PADDING_Y = 40;
		const int BUTTON_FOOTPRINT_X = 60;
		const int BUTTON_FOOTPRINT_Y = 30;
		const int GAME_FORM_OFFSET_Y = 200;
		const int GAME_FORM_OFFSET_X = 200;
		const int BUTTON_SIZE_X = 50;
		const int BUTTON_SIZE_Y = 20;

		int rows, cols, total;
		bool human;
		Button[][] theGame;

		public gameForm()
		{
			InitializeComponent();
		}

		public gameForm(int height, int width, bool _human)
		{

			//The basic component initializtion
			InitializeComponent();

			//Set these form variables
			rows = height;
			cols = width;
			human = _human;

			total = rows * cols;

			this.SetBounds(GAME_FORM_OFFSET_X, GAME_FORM_OFFSET_Y,
				width * BUTTON_FOOTPRINT_X + 2*GAME_FORM_PADDING_X,
				height * BUTTON_FOOTPRINT_Y + 2*GAME_FORM_PADDING_Y);
			
			createGameBoard();
		}

		public void createGameBoard()
		{
			int i, j, x, y;

			//Create an instance of the class that does the event handling
			ClickHandlerClass clicker = new ClickHandlerClass();

			//Create the delegate to handle button presses
			ClickDelegate handler = clicker.buttonclickHandler;


			 //Create the game board
			theGame = new Button[rows][];
			for (i = 0; i < rows; i++)
			{
				theGame[i] = new Button[cols];
				for (j = 0; j < cols; j++)
				{
					//Create the button; it knows its position in the full grid
					theGame[i][j] = new Button();
					//Calculate button positions
					x = GAME_FORM_PADDING_X + j*BUTTON_FOOTPRINT_X;
					y = GAME_FORM_PADDING_Y + i * BUTTON_FOOTPRINT_Y;
					theGame[i][j].SetBounds(x, y, 
						BUTTON_SIZE_X, BUTTON_SIZE_Y);

					//Display button indexes (incremented for looks)
					theGame[i][j].Text = (i + 1) + "," + (1 + j);

					//Subscribe the buttons to the handler that plays the game
					theGame[i][j].Click += clicker.buttonclickHandler(theGame, new ClickArgs(i, j));
					   
					//Add the buttons to the forms' control list
					this.Controls.Add(theGame[i][j]);

				}
			}
		}
	}

	public class ClickHandlerClass
	{
		//Button clicks play the actual game - removing all buttons with a
		//higher index in either row or column than the clicked button.

		public void buttonclickHandler(object sender, ClickArgs e)
		{
			int i,j;

			i = e.Row;
			j = e.Col;

			MessageBox.Show("Click fired for button " + i +  ", " + j);
			//sender.Visible = false;
			
		}

	}




Is This A Good Question/Topic? 0
  • +

Replies To: Writing custom event handler for built-in Click event

#2 Martyr2  Icon User is offline

  • Programming Theoretician
  • member icon

Reputation: 4187
  • View blog
  • Posts: 11,845
  • Joined: 18-April 07

Re: Writing custom event handler for built-in Click event

Posted 27 September 2008 - 10:39 PM

Well this example below shows you how to 1) Create a 2D array of buttons 2) how to add them to the form 3) How to wire an event handler to each button during their creation 4) Handle which button caused the event using the sender and eventargs parameters.

This first part would be placed in something like the form constructor or event of your choosing. Make sure you have created the buttons array at a form level.

The code dynamically creates 16 buttons and wires up each to a custom event we called "buttonclicker".
            // Create our 2D button array
            buttons = new Button[4, 4];

            // Every button move over 60 in width and 50 down
            // This will form a grid
            int height = 50;
            int width = 60;

            // Nested loop creates the buttons
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    // Put a new button in each element of the array
                    // Set its properties like width, height, location, name and text
                    buttons[i, j] = new Button();
                    buttons[i, j].Width = 40;
                    buttons[i, j].Height = 30;
                    buttons[i, j].Top = i * height;
                    buttons[i, j].Left = j * width;
                    buttons[i, j].Name = i.ToString() + " x " + j.ToString();
                    buttons[i, j].Text =  i.ToString() + " x " + j.ToString();

                    // Wire up an event for each button, handing off the job to our function
                    // That function will take a sender and eventargs. 
                    buttons[i, j].Click += new EventHandler(buttonclicker);
                    this.Controls.Add(buttons[i, j]);
                }
            }



Below is the code for the buttonclicker event handler function. Notice that it takes a sender as well as the eventargs. Now eventargs could be a descendant of eventargs if you wish to add more info about the button. However sender is going to be the button that triggered the event so you can get the name of the button in the array. Here is how it may look...

private void buttonclicker(object sender, EventArgs e)
{
     // Show what button was pressed
     Button btn = (Button)sender;
     MessageBox.Show(btn.Name);
}



This event handling function for example will show the name of the button that triggered the event. We do this by casting the sender to a button and ask it to show its name property. So in our example the messagebox will show us "1 x 1" for instance for the second button on the second row. You can use this sender object reference to hide the button, or simply use the event to manipulate other buttons based on the button clicked etc.

Hope this makes sense to you and is what you are asking about. Enjoy!

"At DIC we be dynamic button making code ninjas... and at xmas time we make them with gum drops and candy canes!" :snap:
Was This Post Helpful? 1
  • +
  • -

#3 vertizor  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 9
  • Joined: 27-September 08

Re: Writing custom event handler for built-in Click event

Posted 28 September 2008 - 09:16 AM

A quick note - this appears to be working so far, thanks! However, I am not sure that

Now eventargs could be a descendant of eventargs if you wish to add more info about the button.

is true (II'm not sure how to use the quote feature, sorry). The problem is, if I simply try to replace EventArgs with my inherited ClickArgs, I get an error that this does not match the signature of an event handler.

Now, using the above code it can still work, it's just a little less elegant ... I have to parse the name or the exact screen position to retrieve the buttons position in the grid. Before doing either, I will be trying this with a custom button class ... wish me luck!
Was This Post Helpful? 0
  • +
  • -

#4 baavgai  Icon User is online

  • Dreaming Coder
  • member icon

Reputation: 5641
  • View blog
  • Posts: 12,358
  • Joined: 16-October 07

Re: Writing custom event handler for built-in Click event

Posted 28 September 2008 - 09:58 AM

All controls, like Button, have a property called Tag. Tag is just a place to stick an object, it's null by default. So, if you want to store all manner of interesting information to reference later, stick it in Tag. Honestly, with that in mind, I wouldn't really bother with a 2D array unless you really, really needed it for some reason.

So, borrowing from Martyr's good example.

class ButtonInfo {
	public int x;
	public int y;
	public ButtonInfo(int x, int y) {
		this.x = x;
		this.y = y;
	}
	public override ToString() { return "BI: (" + x + "," + y + ")"; }
}


int posX;
int posY = 100;
for (int y = 0; y < 4; y++) {
	posX = 100;
	for (int x = 0; x < 4; x++) {
		Button b = new Button();
		b.Width = 40;
		b.Height = 30;
		b.Top = posY;
		b.Left = posX;
		//b.Name;
    		b.Text =  "X";
		b.Tag = new ButtonInfo(x,y);

		b.Click += new EventHandler(buttonclicker);
		this.Controls.Add(B)/>;
		posX += 60;
	}
	posY += 50
}

private void buttonclicker(object sender, EventArgs e) {
     ButtonInfo bi = (ButtonInfo)((Button)sender).Tag;
     MessageBox.Show(bi);
}



Now, rather than using another property to store your data or needing to parse a string to get it out, you can just use your custom object. More than that, the object can store anything you like, like state changes. Additionally, you don't need to maintain an array, just pull the button you need out of the form controls collection if you need it.

Hope this helps.
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1