C++/CLI 将其他参数传递给事件处理方法



我正在尝试编写一个在运行时创建大量按钮的 C++/CLI 表单应用程序: 我有一个字符串向量,每个字符串都会创建一个按钮:

std::vector<std::string> strings;
/*
    string being initialized with values from file
*/
for ( std::vector<std::string>::iterator it = heroes.begin(); it != heroes.end(); ++it ) {
    Button ^ button = gcnew Button;
    /*
        button being customized depending on the string
    */
    buttonPannel->Controls->Add(button);
}

现在我要做的是为每个按钮添加一个事件处理程序,以便将用于自定义按钮的字符串传递给处理方法。

在 c# 中,我会写类似的东西

button->Click += new EventHandler((sender, args) => button_Click(s, e, *it));

如何在 C++/CLI 中实现此目的?

您可以执行与 C# 代码完全相同的操作,但我宁愿使用 Button 类上的现有属性来保存所需的额外数据。

在这种情况下,Tag属性似乎是合适的:其目的是保存与控件密切相关的任何额外数据,因此这对于驱动程序逻辑的字符串来说似乎是正确的。(您可能需要使其成为托管String^对象,而不是std::string,但这很容易转换。

void Form1::CreateButtons()
{
    for (std::vector<std::string>::iterator it = heroes.begin(); it != heroes.end(); ++it)
    {
        Button ^ button = gcnew Button;
        button->Tag = marshal_as<String^>(*it);
        button->Click += gcnew EventHandler(this, &Form1::button_Click);
        buttonPanel->Controls->Add(button);
    }
}
void Form1::button_Click(Object^ sender, EventArgs^ e)
{
    Control^ senderControl = dynamic_cast<Control^>(sender);
    String^ heroName = nullptr;
    if(senderControl != nullptr)
        heroName = dynamic_cast<String^>(senderControl->Tag);
    if(heroName == nullptr)
    {
        // Something went wrong. Bail out.
        return;
    }    
    // ...
}

如果您确实想执行等效的 C# 代码:您的 C# lambda 正在对it变量执行变量捕获。我们可以在 C++/CLI 中进行变量捕获,只是需要更多手动操作。

(注意:您的 C# 示例捕获的是迭代器,而不是字符串,不确定这是否是预期内容。我写这个是为了捕获字符串对象。

ref class EventHandlerStringCapture
{
public:
    EventHandlerStringCapture(std::string str,
        Action<Object^, EventArgs^, std::string>^ handler)
    {
        this->str = str;
        this->handler = handler;
    }
    void eventHandler(Object^ sender, EventArgs^ e)
    {
        this->handler(sender, e, this->str);
    }
private:
    std::string str;
    Func<Object^, EventArgs^, std::string>^ handler;
}
void Form1::CreateButtons()
{
    for (std::vector<std::string>::iterator it = heroes.begin(); it != heroes.end(); ++it)
    {
        Button ^ button = gcnew Button;
        // The variable to capture.        
        std::string str = *it;
        // The actual event handler: a method in the current class.
        Action<Object^, EventArgs^, std::string>^ actualHandler = 
            gcnew Action<Object^, EventArgs^, std::string>(this, &Form1::button_Click);
        // Pass both the variable to capture and the 
        // actual event handler to a helper object.
        EventHandlerStringCapture^ ehsc = 
            gcnew EventHandlerStringCapture(str, actualHandler);
        // Grab the two-parameter event handler from the helper object, 
        // and make that the click handler.
        button->Click += 
            gcnew EventHandler(ehsc, &EventHandlerStringCapture::eventHandler);
        buttonPanel->Controls->Add(button);
    }
}
void Form1::button_Click(Object^ sender, EventArgs^ e, std::string heroName)
{
    // ...
}

(注意:我不在编译器,所以可能存在语法错误。

显然,在按钮对象上使用现有属性更简单,但这相当于 C++/CLI 在后台执行的操作。

相关内容

  • 没有找到相关文章

最新更新