Click here to Skip to main content
15,867,704 members
Please Sign up or sign in to vote.
3.67/5 (3 votes)
See more:
I have a panel control on a form where I place a list of names and a Cancel button beside each name. The number of Name/Button combinations is determined at run time, with each label and button added dynamicly.

I need to pass a string containing the ID to the buttons click event, but I am struggling with how to do this.

This is the code as it stands
		for each(CValidationLog^ candidate in ValidationLogList)
		{
			// Create a dynamic picture box
			m_Stream = nullptr;
			array<Byte> ^byteBLOBData = gcnew array<Byte>(0);
			if (candidate->p_Photo != nullptr)
			{
				byteBLOBData = candidate->p_Photo;				
			}
			m_Stream = gcnew MemoryStream(byteBLOBData);
			
			PictureBox ^picPassenger = gcnew PictureBox();
			picPassenger->Location = Drawing::Point(p.X, p.Y);
			picPassenger->BorderStyle = System::Windows::Forms::BorderStyle::Fixed3D;
			picPassenger->SizeMode = System::Windows::Forms::PictureBoxSizeMode::StretchImage;
			picPassenger->Size = System::Drawing::Size(200, 190);
			try
			{
				picPassenger->Image = Image::FromStream(m_Stream);
			}
			catch(Exception ^)
			{
				picPassenger->Image = picPassenger->ErrorImage;
			}
			m_ToolTip->SetToolTip(picPassenger, L"Image Tooltip");
			// Add dynamic label to Validated Panel
			pnlValidated->Controls->Add(picPassenger);

			// Create a dynamic label
			Label ^lblPassenger = gcnew Label();
			lblPassenger->Location = Drawing::Point(p.X + 220, p.Y);
			lblPassenger->BorderStyle = System::Windows::Forms::BorderStyle::Fixed3D;
			lblPassenger->BackColor = System::Drawing::SystemColors::Control;
			lblPassenger->Size = System::Drawing::Size(200, 55);
			lblPassenger->Text = candidate->p_Person_ID + L" " + candidate->p_Forename + L" " + candidate->p_Surname;
			lblPassenger->Font  = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 15.75F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point, 
				static_cast<System::Byte>(0)));
			m_ToolTip->SetToolTip(lblPassenger, L"Label Tooltip");

			// Add dynamic label to Validated Panel
			pnlValidated->Controls->Add(lblPassenger);

			// Create a dynamic button
			Button ^btnCancelThisValidation = gcnew Button();
			btnCancelThisValidation->Location = Drawing::Point(p.X + 220, p.Y + 60);
			btnCancelThisValidation->Size = System::Drawing::Size(200, 130);
			btnCancelThisValidation->BackColor = System::Drawing::SystemColors::Control;
			btnCancelThisValidation->Text = L"Cancel";
			btnCancelThisValidation->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 15.75F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point, 
				static_cast<System::Byte>(0)));
			btnCancelThisValidation->Click += gcnew System::EventHandler(this,&frmIntercept::Process_btnCancelThisValidation_Click);
//			btnCancelThisValidation->Click += gcnew System::EventHandler(candidate,&frmIntercept::Process_btnCancelThisValidation_Click);
			m_ToolTip->SetToolTip(btnCancelThisValidation, L"Button Tooltip");
			// Add dynamic button to Validated Panel
			pnlValidated->Controls->Add(btnCancelThisValidation);

			Y += 200;
			p = Drawing::Point(X,Y);// set the point for the next record.
		}	
....
void VTIntercept::frmIntercept::Process_btnCancelThisValidation_Click(System::Object^ sender,System::EventArgs^ e)
{
}


I need the click event to be able to access the correct candidate. Now I have an idea forming where the index of the button clicked will match the index of the element in the candidate list. But there has to be a neater way.
Posted
Updated 2-Jul-12 8:36am
v2
Comments
Sergey Alexandrovich Kryukov 2-Jul-12 14:11pm    
You don't nee to pass a string value to the event, you need to pass it to an event handler, which is a different thing. Not clear how can it be a problem.
--SA
Ger Hayden 2-Jul-12 14:37pm    
The problem is a lack of ability on my part...
Sergey Alexandrovich Kryukov 2-Jul-12 14:49pm    
How about your ability to read and understand long answers? I've provided a whole article explaining these thing to you... :-)
--SA
Ger Hayden 2-Jul-12 14:51pm    
That too! Got it now. I'll go through it in the morning. Much appreciated.
Sergey Alexandrovich Kryukov 2-Jul-12 16:21pm    
My pleasure. Please see if you can get it without writing in it again in C++/CLI, but if this is a problem, please ask, I'll try to help.
If you can already see it's the solution, please accept the answer formally (green button).
--SA

Every time an event is triggered, the control that raised the event is already passed to the handler as the sender parameter. You can cast this to the appropriate class and use any of it's properties, including it's name, location, already. You should not need to add any additional identification.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 2-Jul-12 14:47pm    
This is not the only mechanism; and using sender has that down-side that a type case is requires. There is another hidden parameter to be used...
Please see my answer.
--SA
Please see my comment to the question. As you need to pass some data to event handler, and not to the event (not clear what would it possibly mean), the problem is pretty trivial.

There are two approaches to passing of the data to a handler. First of all, you should decide if you are using a named method for an event handler, or an anonymous one.

Let's start with some "regular", named method. For simplicity, let's assume you need to handle some button Click events. In the context of this problem, the type of an event arguments and event handler does not really matter. Let's see:
C#
class SomeClass { //could be a form or WPF window class, it does not really matter

    void SomeSetupMethod() {
         MyButton.Click += MyButtonClickHandler;
    } //SomeSetupMethod

    void SomeSetupMethod(object sender, System.EventArgs eventArgs) {
        if (id != null) //you can use id, because this method is an instance one (non-static)
            //...
        //which is same as if (this.id != null)... //"this" is passed to all instance methods
        //
        //do something...
    } //SomeSetupMethod

    // some members...

    string id; 

} //class SomeClass

As you can see, in this context, when you have a method used as a event handler and some member you want to use to pass data to a handler are the members of the same class, you can freely use any class members (such as id you are interested in) in the implementation of the handler. The question is: why? The answer is: because you can use an instance (non-static) method as a handler. An instance method has an additional parameter "this" passed to provide the access to all instance (non-static) members of some instance of a class, actually, "this" is a reference to a particular instance of the class, the one used at the call. In the operator "+=" the operand MyButtonClickHandler represents the delegate instance which passes both address of the method to be called, with the particular "this" reference. This delegate instance object is copied to the invocation list of the event instance, which guaranteed a correct call. With right "this", and, hence, indirectly, with right value of id.

Another method is related to the anonymous delegates. The mechanism of passing parameter is much harder to understand in this case. It is related to the notion of closure. So, first of all, try to understand closures:
http://en.wikipedia.org/wiki/Closure_%28computer_science%29[^].

This is not the best place to explain how closures work in your case. It could be a subject of a whole article. I'll just give you the idea how it might look in code:
C#
class SomeClass { //could be a form or WPF window class, it does not really matter

    void SomeSetupMethod() {
         MyButton.Click += delegate(object sender, System.EventArgs eventArgs) {
             if (id != null) //read about using closures to understand why this is possible
                //...
             //... do something, best of all, call some other method here, with appropriate parameters
         }; //MyButton.Click
    } //SomeSetupMethod

    // some members...

    string id; 

} //class SomeClass


Also, if you use the .NET Framework version newer than v.2.0, which is usually the case, you can also use lambda syntax, which nicely simplifies writing the anonymous methods, and not only event handlers:
C#
//...

void SomeSetupMethod() {
     MyButton.Click += (sender, eventArgs) => {
         if (id != null) //read about using closures to understand why this is possible
            //...
         //... do something, best of all, call some other method here, with appropriate parameters
     }; //MyButton.Click

//...
} //SomeSetupMethod


In this syntax, you don't have to write exact argument types (which is especially good because they are often unused); their types are determined by the compiler using type inference from the known event type. Please see:
http://en.wikipedia.org/wiki/Type_inference[^],
http://msdn.microsoft.com/en-us/vstudio/jj131514.aspx[^].

You follow-up questions are welcome.

—SA
P.S.: Sorry, I've written it all in C# because I forgot you used C++ while I was writing this text, and writing in C++ would take some more of my time. I hope this is enough for you to get the idea. If you cannot figure out how to express similar things in C++, please ask me another question, I'll try to help.
 
Share this answer
 
v5
Comments
Ger Hayden 3-Jul-12 3:43am    
Thanks Again Sergey. The translation was no difficutly - but I hit an issue with "SetUpSomeMethod" because I am using a loop. The compiler didnt want me making new function definitions in it! I assume that if the loop were to call an instance of a new class to conduct its functionality on each iteration then you solution would work as is. I had about 90 minutes with it on the way to work this morning. I'll explore some more on the route home.

I have also found that since all I need is an ID, I can cheat by passing it to Process_btnCancelThisValidation as the button name...which works until I need a second piece of data, then I have to look at applying your solution.
Sergey Alexandrovich Kryukov 6-Jul-12 18:39pm    
Well, you are very welcome. I did not get why you have problem with the loop, as -- what difference can it make? If you still have a problem, feel free to ask another question.
Good luck,
--SA

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