2011-01-27 16 views
14

Necesito poder pasar dos objetos al método que se dispara cuando hago clic en un botón. ¿Cómo hago esto?¿Cómo paso las variables a un método de evento de botones?

Hasta ahora he estado buscando en la creación de una modificados eventArgs:

public class CompArgs : System.EventArgs 
    { 
    private object metode; 
    private Type typen; 

    public CompArgs(object m, Type t) 
    { 
     this.metode = m; 
     this.typen = t; 
    } 

    public object Metode() 
    { 
     return metode; 
    } 

    public Type Typen() 
    { 
     return typen; 
    } 
} 

Pero ¿cómo lo uso? ¿Es posible de alguna manera anular el evento click del botón para usar un eventhandler personalizado, que toma CompArgs como parámetro?

private void button1_Click(object sender, EventArgs e) 
     { 


      Assembly assembly = Assembly.LoadFile(@"c:\components.dll"); 

      int counter = 0; 

      foreach (Type type in assembly.GetTypes()) 
      { 
       if (type.IsClass == true) 
       { 

        Button btn = new Button(); 
        btn.Location = new Point(174 + (counter * 100),10); 
        btn.Size = new Size(95, 23); 
        btn.Name = type.Name; 
        btn.Text = type.Name; 
        btn.UseVisualStyleBackColor = true; 


        this.Controls.Add(btn); 

        object obj = Activator.CreateInstance(type); 

        //I need to pass on obj and type to the btn_Click 
        btn.Click += new eventHandler(btn_Click); 

        counter++; 
       } 
      } 
     } 

Y el evento de método en el que lo necesito:

private void btn_Click(object sender, CompArgs ca) 
     { 
       MessageBox.Show((string)ca.Typen().InvokeMember("getMyName", 
          BindingFlags.Default | BindingFlags.InvokeMethod, 
          null, 
          ca.Metode(), 
          null)); 

     } 
+0

se puede anular el método OnClick mediante la derivación de la clase Button. Han agregado una respuesta usando esta técnica. – Ian

Respuesta

5

Cant que acaba de establecer una propiedad o variable de miembro en el formulario que aloja el botón y acceder a ellos desde el evento de clic de botón?

EDIT: a medida sugerencia clase de botón después de comentario de retroalimentación (no es lo mismo que el anterior sugerencia)

class MyButton : Button 
{ 
    private Type m_TYpe; 

    private object m_Object; 

    public object Object 
    { 
     get { return m_Object; } 
     set { m_Object = value; } 
    } 

    public Type TYpe 
    { 
     get { return m_TYpe; } 
     set { m_TYpe = value; } 
    } 
} 




Button1Click(object sender, EventArgs args) 
{ 
    MyButton mb = (sender as MyButton); 

    //then you can access Mb.Type 
    //and Mb.object 
} 
+1

@WraithNath - He usado este enfoque antes, pero siento que es una manera poco limpia de hacerlo. Necesito el botón para hacer referencia a los objetos correctos así que la manera en que lo hice la última vez fue almacenar los objetos en una lista. Guardé el índice relativo de un objeto de botones en su propiedad Tag y luego lo analicé cuando lo necesité. – Bildsoe

+0

Hola, ¿de dónde viene la información que desea pasar al evento click? ¿existe dentro del control de botón ya activado en el formulario? Creo que la única forma de poder cambiar el manejador de clic de botón es implementar su propio control de botón o una derivada de los formularios de Windows. Puede almacenar los objetos que desea utilizar en el evento de clic en la etiqueta del botón como una matriz o un tipo personalizado y luego simplemente enviar al remitente como un botón y recuperar la etiqueta. ¿Está el botón en un formulario emergente donde el usuario selecciona y opción y cierra el formulario? – WraithNath

+0

@WraithNath - He incluido más código. El concepto que describes es cómo lo manejé antes. Pero como dije, se siente un poco ... sucio. – Bildsoe

1

No puede utilizar su propia clase de argumento de evento personalizado para una firma de controlador de eventos predefinidos. Al menos, el tipo de argumento de evento personalizado nunca será utilizado por ninguna llamada predeterminada al controlador (que solo será del tipo EventArgs en el caso de un botón); podría, potencialmente, llamar al manejador usted mismo, pasando su tipo personalizado, sin embargo, necesitaría tener la lógica para devolverlo desde un EventArgs al que se lo había lanzado.

Como una posible solución (según su situación), considere un tipo compuesto para encapsular los elementos que necesita, como con su tipo de argumento de evento, pero mantenga la instancia requerida como una variable accesible que puede utilizarse desde el evento manejador, o, al menos, por el/los método/es que invoca el controlador par.

Por ejemplo, definir el tipo de ...

public class MyType 
{ 
    public object AccessibleItem { get; set; } 
} 

Y, en su clase de formulario ...

private MyType MyTypeInstance = new MyType(); 

private void Button_Click(object sender, EventArgs e) 
{ 
    //here we can set the item, if needs be... 
    MyTypeInstance.AccessibleItem = new Anything(); 
    //or access the item to use as required... 
    DoSomeMagicWithMyObject(MyTypeInstance.AccessibleItem); 
} 

EDIT:

bien, mirando a su código de corriente I solo puedo ofrecerte esto por ahora (no agrega los elementos al contenedor de control de formularios y utiliza un iterador variable dentro de Linq (que creo que está mal visto o simplemente mal, pero ... bueno, pero bueno ... .):

private void BuildButtonToObjectDictionary() 
    { 
     int counter = 0; 
     var assembly = Assembly.LoadFile(@"c:\components.dll"); 

     var buttonToObjectDictionary = (
      from type in assembly.GetTypes() 
      where type.IsClass && !type.IsAbstract 
      select new 
      { 
       Button = new Button 
       { 
        Name = type.Name, 
        Text = type.Name, 
        Size = new Size(95, 25), 
        Location = new Point(175 + (counter * 100), 10), 
        UseVisualStyleBackColor = true 
       }, 
       Item = Activator.CreateInstance(type), 
       Index = counter++ 
      }); 
    } 
+0

Pero tendré muchos botones con sus propios objetos que necesitan ser accedidos. Cómo puedo hacer esto. Anteriormente almacené los objetos en una lista. Guardé el índice relativo de un objeto de botones en su propiedad Tag y luego lo analicé cuando lo necesité. – Bildsoe

+0

@Bildsoe: ¿Dónde se crean las instancias? Es el mismo tipo de concepto, pero podría usar un "Diccionario", donde la "Llave" es una referencia a un botón y está asociado con el "Valor" apropiado - o incluso un "Hashtable". –

+0

He incluido más código para mostrarte lo que intento lograr. – Bildsoe

0

necesitaría para ver más código para dar una mejor respuesta, pero podría crear un evento que tiene sus CompArgs como parámetro y se activa cuando el buttonEvent es capturado

0

Si archivo que yourForm.Designer.cs abiertas verá todos los automóviles código generado por VS. Aquí puede modificar el método llamado al hacer clic en el botón (o agregar un segundo método).

this.yourButton.Location = new System.Drawing.Point(211, 51); 
this.yourButton.Name = "yourButton"; 
this.yourButton.Size = new System.Drawing.Size(75, 23); 
this.yourButton.TabIndex = 0; 
this.yourButton.Text = "yourButton"; 
this.yourButton.UseVisualStyleBackColor = true; 
this.yourButton.Click += new System.EventHandler(this.yourMethodHere(object1, object2); 

Espero que esto ayude.

+0

¿es esto posible? no es el remitente y el evento Arreglos siempre pasado como parámetros? – Bildsoe

+1

Por lo que puedo ver, esto no funcionará en absoluto. E incluso si lo hiciera, siempre serían los mismos dos argumentos especificados como parámetros, en lugar de ser invocados y los argumentos especificados por invocación.Y si ese fuera el comportamiento deseado, aún no se compilaría, debido al paréntesis faltante. –

2

No estoy seguro de si esto existe en Winforms pero lo hace en WPF: Hay un objeto "tag" en todos los controles al que puede adjuntar cualquier objeto.Puede guardar el objeto que desea pasar y luego en el controlador de eventos leerlo de nuevo desde el objeto emisor.

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    var note = (sender as FrameworkElement).Tag as Note; 
    //Do something with note here 
} 
+0

Igual va para Winforms – flq

+1

Aunque no es una forma muy elegante. Tienes que saber sobre la etiqueta y qué esperar en ella. – Ian

3

Crearía un nuevo botón y anularía el método OnClick. En lugar de pasar los EventArgs, pase una nueva clase derivada con sus miembros adicionales.

En el delegado que recibe el evento, transfiera los EventArgs dados a la clase más derivada que espera obtener, configure alternativamente un nuevo evento que se active al mismo tiempo cuando se presiona el botón y conéctese a ese en cambio, para hacer las cosas más implícitas.

Código Ejemplo:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 

     ButtonEx b1 = new ButtonEx(); 
     b1.OnCustomClickEvent += new ButtonEx.OnCustomClickEventHandler(b1_OnCustomClickEvent); 
    } 

    void b1_OnCustomClickEvent(object sender, ButtonEx.CustomEventArgs eventArgs) 
    { 
     string p1 = eventArgs.CustomProperty1; 
     string p2 = eventArgs.CustomProperty2; 
    } 
} 

public class ButtonEx : Button 
{ 
    public class CustomEventArgs : EventArgs 
    { 
     public String CustomProperty1; 
     public String CustomProperty2; 
    } 

    protected override void OnClick(EventArgs e) 
    { 
     base.OnClick(e); 
     if(OnCustomClickEvent != null) 
     { 
      OnCustomClickEvent(this, new CustomEventArgs()); 
     } 
    } 

    public event OnCustomClickEventHandler OnCustomClickEvent; 
    public delegate void OnCustomClickEventHandler(object sender , CustomEventArgs eventArgs); 
} 
+1

muy buena respuesta –

32

Wow, ustedes están haciendo esto por completo a difícil. No hay necesidad de ninguna clase personalizada o anulación de método. En este ejemplo, solo necesito pasar un número de índice de pestaña. Puede especificar lo que desee, siempre que su método espere ese tipo de valor.

button.Click += (sender, EventArgs) => { buttonNext_Click(sender, EventArgs, item.NextTabIndex); }; 

void buttonNext_Click(object sender, EventArgs e, int index) 
    { 
     //your code 
    } 
+1

No estoy seguro de por qué las personas no solo usan esta respuesta. Mucho más simple – Larry

+0

Mucho más elegante y delgado que el derivado de la clase de control. –

+1

Hola chicos, sé que esta es una publicación más antigua, pero pensé que señalaría que si se despliega una variable en el código anterior, VS emitirá un ataque. Tengo un botón que quería enviar un conmutador al pulsar tecla, utilicé el código anterior (que es genial) pero no me gustó la variable booleana ... esta es la firma del método: 'private void UpdateDBButton_Click (object remitente, EventArgs e , bool fullReset) 'y la línea del controlador de eventos:' UpdateDBButton.Click + = (sender, EventArgs) => {bool fullReset = false; UpdateDBButton_Click (remitente, EventArgs, fullReset); }; ' –

1

Puede usar la propiedad Tag del botón. Se puede añadir un valor de cadena a esta propiedad desde la ventana de propiedades de diseño y luego recogerlo dentro del manejador como tan:

private void MyButton_Click(object sender, EventArgs e) 
    { 
     string tagValue = ((Button) sender).Tag; 

     if(tag == "blah") 
     { 
      // Do something 
     } 
    } 
Cuestiones relacionadas