动态按钮上需要委托/事件帮助 [英] Delegate/Event help needed on dynamic buttons

查看:68
本文介绍了动态按钮上需要委托/事件帮助的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在窗体上有一个面板控件,在该控件中,我在每个名称旁边放置了一个名称列表和一个取消"按钮.名称/按钮组合的数量是在运行时确定的,每个标签和按钮都是动态添加的.

我需要将包含ID的字符串传递给按钮click事件,但是我在如何做到这一点上很挣扎.

这就是目前的代码

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.

推荐答案

每次触发事件时,引发事件的控件都已作为sender传递给处理程序.范围.您可以将其强制转换为适当的类,并使用其任何属性,包括其名称,位置.您不需要添加任何其他标识.
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.


请参阅我对问题的评论.由于您需要将一些数据传递给事件处理程序,而不是传递给事件(不清楚可能意味着什么),因此问题很简单.

有两种方法可以将数据传递给处理程序.首先,应该确定是对事件处理程序使用命名方法,还是对匿名处理程序使用匿名方法.

让我们从一些常规"的命名方法开始.为了简单起见,假设您需要处理一些按钮Click事件.在此问题的上下文中,事件参数和事件处理程序的类型实际上并不重要.让我们看看:
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:
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


如您所见,在这种情况下,当您有一个用作事件处理程序的方法,并且要用于将数据传递给处理程序的某些成员是同一类的成员时,您可以自由使用任何类成员(例如id您感兴趣的)在处理程序的实现中.问题是:为什么?答案是:因为您可以使用实例(非静态)方法作为处理程序.实例方法具有附加的参数"this",以提供对类的某个实例的所有实例(非静态)成员的访问,实际上,"this"是对类的特定实例的引用.在电话.在运算符"+ ="中,操作数MyButtonClickHandler表示委托实例,该实例传递要调用的方法的两个地址,并带有特定的"this"引用.将该委托实例对象复制到事件实例的invocation list中,以确保正确的调用.使用正确的"this",因此间接使用正确的值id.

另一种方法与匿名委托有关.在这种情况下,传递参数的机制很难理解.它与闭包的概念有关.因此,首先,尝试了解闭包:
http://en.wikipedia.org/wiki/Closure_%28computer_science%29 [ ^ ].

这不是解释闭包在您的情况下如何工作的最佳位置.它可能是整篇文章的主题.我只是告诉您它在代码中的外观:


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:

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



另外,如果使用的是通常比v.2.0更新的.NET Framework版本,则还可以使用lambda语法,它可以很好地简化编写匿名方法的过程,而不仅仅是事件处理程序:



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:

//...

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



使用这种语法,您不必编写确切的参数类型(这特别好,因为它们经常未使用);它们的类型由编译器根据已知事件类型使用类型推断确定.请参阅:
http://en.wikipedia.org/wiki/Type_inference [ http://msdn.microsoft.com/en-us/vstudio/jj131514.aspx [ ^ ].

欢迎您提出后续问题.

—SA
PS :抱歉,我已经用C#编写了所有内容,因为我在撰写本文时忘记了使用C ++,而用C ++编写则需要更多时间我的时间.我希望这足以让您理解.如果您不知道如何在C ++中表达类似的内容,请问另一个问题,我会尽力提供帮助.



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.


这篇关于动态按钮上需要委托/事件帮助的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆