views:

77

answers:

2

Hello, In C#, We can call a new function from button click with arguments like this,

    ////My function
    public static void Method1(int x)
    {
        Console.WriteLine("Method 1");
    }

and set this function on click event of a command button like this,

button1.Click += delegate { mydelegate with argument };

Eg:

delegate void Procedure( int x);

public partial class Window1 : Window
{
    public Window1()
    {
        Procedure pProcedure = new Procedure(Method1);
        InitializeComponent();

        button1.Click += delegate { pProcedure(10); };
    }

    public static void Method1(int x)
    {
        Console.WriteLine("Method 1");
    }
}

Now when we click on the button1, then the function "Method1" will be invoke.

How can I do the same using C++/CLI?

I need to find the added delegate from the click event and need to remove. How can i do this?

+2  A: 

If you're asking about how to use anonymous delegates in C++/CLI, then the answer is you can't. In C++/CLI, delegates must be bound to a named function.

To accomplish what inline anonymous delegates actually do in C#, you can use the concept of a 'functor' or function object. The following C++/CLI sample illustrates how to create a function object and "bind" it to a specific value and then show how to use it as an event subscriber.

using namespace System;

// Sample class with one event 'Started' 
public ref class Widget
{ 
public:
    Widget()
    {
    }

    event EventHandler ^ Started;

    void Start()
    {
        Console::WriteLine("Starting...");
        Started(this, EventArgs::Empty);
    }
};

// Declare 'functor' class to capture state
private ref class Functor
{
public:
    Functor(int input)
        : input_(input)
    {
    }

    // This is what we will use as the handler method
    void Handler(Object ^ sender, EventArgs ^ e)
    {
        Console::WriteLine(L"Invoked with input {0}.", input_);
    }

private:
    int input_;
};

// Entry point
int wmain(int argc, wchar_t ** argv)
{
    // Create a functor to capture value '10'
    Functor ^ f = gcnew Functor(10);

    Widget ^ widget = gcnew Widget();

    // Subscribe to event using functor's handler
    // (note that we bind to the instance 'f' here)
    EventHandler ^ handler = gcnew EventHandler(f, &Functor::Handler);
    widget->Started += handler;

    // Should print "Invoked with input 10."
    widget->Start();

    // Remove the handler
    widget->Started -= handler;

    // Should not print anything extra now
    widget->Start();

    return 0;
}
bobbymcr
Thank you for your answer.
sabeesh
You can't *YET*. C++0x adds lambdas, giving C++ a syntax for anonymous methods for the first time. Personally I'm very glad Microsoft waited for the standard committee to reach consensus on syntax instead of adding some non-portable extensions and ending up with different syntax for lambdas in managed vs native code.
Ben Voigt
I need to find the added delegate from the click event and need to remove. How can i do this?
sabeesh
Assign the handler to a variable and use the `-=` operator; I updated my code sample to show this.
bobbymcr
Thank you for your help. But here we create an eventhandler with object of 'f' and add to the eventhandler of widget class like " EventHandler ^ handler = gcnew EventHandler(f, widget->Started += handler;" and we can remove it using '-=' with that event handler
sabeesh
Thank you for your help. But my problem is that, I create this eventhandler and assigned it to the widget in a loop. So when the loop execute, at first time its ok. But when the loop continue, then before adding a new eventhandler with a new object of 'f', I need to check whether any event handler is added to that widget with type of 'functor', if it is I need to remove that old handler and add a new one. How can I check and remove it.
sabeesh
The above example is the "correct" way to do this; the subscriber should generally be responsible for cleaning up. In C#, there are various hacks to achieve something close to what it sounds like you're asking for (e.g. reflection, or the use of `GetInvocationList()`). I'm not sure the same techniques would work in C++/CLI and I would recommend against this anyway.
bobbymcr
+1  A: 

Thank you for your help. With your help I can solve my problem. The solution is like this,

//FirstWindow.h
#pragma once

using namespace System; using namespace System::Windows; using namespace System::Windows::Controls;

ref class Functor;

ref class FirstWindow : Window { Canvas^ maincanvas; Button^ addbutton1; Button^ addbutton2; Functor^ pFunctor; public: FirstWindow(void); void InitControls(void); void MyFunction( int x, int y );

};

//FirstWindow.cpp #include "FirstWindow.h" #include "Functor.h"

FirstWindow::FirstWindow(void) { Title = "First Avalon App"; Width = 400; Height = 400; ResizeMode = System::Windows::ResizeMode::NoResize;

InitControls();

}

void FirstWindow::InitControls(void) { addbutton1 = gcnew Button(); addbutton1->Width = 80; addbutton1->Height = 25; addbutton1->Content = "Add"; pFunctor = gcnew Functor(this, 10, 20); addbutton1->Click += gcnew RoutedEventHandler( pFunctor, &Functor::Handler);

    Canvas::SetTop(addbutton1, 45);
    Canvas::SetLeft(addbutton1, 200);


    pFunctor = gcnew Functor(this, 100, 200);
    addbutton2 = gcnew Button();
    addbutton2->Width = 80;
    addbutton2->Height = 25;
    addbutton2->Content = "Add";
    addbutton2->Click += gcnew RoutedEventHandler(pFunctor, &Functor::Handler);

    Canvas::SetTop(addbutton2, 85);
    Canvas::SetLeft(addbutton2, 200);


    maincanvas = gcnew Canvas();        

    maincanvas->Children->Add(addbutton1);
    maincanvas->Children->Add(addbutton2);
    Content = maincanvas;

}

void FirstWindow::MyFunction( int x, int y ) { MessageBox::Show("This function is call by Button Click with values " + x.ToString() + " , " + y.ToString() ); }

//Functor.h #pragma once

using namespace System; using namespace System::Windows; using namespace System::Windows::Controls;

ref class FirstWindow;

private ref class Functor { public: Functor(FirstWindow^ pFirstWindow, int pFirstArg, int pSecArg);

// This is what we will use as the handler method
void Handler(Object ^ sender, RoutedEventArgs ^ e);

private: int m_pFirstArg; int m_pSecArg; FirstWindow^ m_pFirstWindow; };

//Functor.cpp

#include "Functor.h" #include "FirstWindow.h"

Functor::Functor(FirstWindow^ pFirstWindow, int pFirstArg, int pSecArg) : m_pFirstWindow( pFirstWindow ), m_pFirstArg(pFirstArg), m_pSecArg( pSecArg ) {

}

void Functor::Handler(Object ^ sender, RoutedEventArgs ^ e) { if ( m_pFirstWindow ) m_pFirstWindow->MyFunction(m_pFirstArg, m_pSecArg );

}

Now when we click on button one, then the application call the function "MyFunction" with value 10,20 and when we click on button 2 then the same function "MyFunction" with value 100,200.

Thank you for your help.

Sabeesh

sabeesh
Please edit your question instead of adding an answer here. You should delete this.See my updated response for the answer to your follow up question.
bobbymcr