¿Puedo asignar un método a múltiples eventos basados ​​en formularios?

Estoy construyendo un formulario y tiene varios controles numericUpDown, varios controles de casilla de verificación y algunos cuadros de texto, etc. Cada control tiene un método de evento (CheckedChanged, ValueChanged, etc.) que se activa y hace algo, pero mi pregunta principal es esta:

Lo que quiero hacer es ejecutar un método único que actualice un campo de texto en mi formulario, pero actualmente lo tengo repetido 24 veces. Esto funciona, pero siento que debe haber una mejor manera... A continuación se muestra un ejemplo de lo que tengo hasta ahora.

    private void button3_Click(object sender, EventArgs e)
    {
    // Code Specific to the Buton3_Click
    UpdateTextLabel();
    }
    private void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
    // Code Specific to the checkBox1_CheckChanged
    UpdateTextLabel();
    }
    private void numericUpDown1_ValueChanged(object sender, EventArgs e)
    {
    // numericUpDown1 specific code ....
    UpdateTextLabel();
    }
    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
    // comboBox1 specific stuff ...
    UpdateTextLabel();
    }
   // .... and so on for every method ....

¿Hay una mejor manera de lograr esto? Quiero decir "si se hace clic en cualquier control o se cambia ... HAGA ESTO "UpdateTextLabel ()" pero no estoy seguro de cómo hacerlo. Feliz de ser dirigido a la respuesta ya que las preguntas que escribí en la búsqueda no parecían ser las "preguntas correctas"...

¡Gracias!

preguntado el 02 de julio de 12 a las 13:07

3 Respuestas

sí, cualquier evento de cualquier control puede compartir el mismo método de controlador de eventos siempre que sus delegados de controlador de eventos sean los mismos, en este caso, los delegados de controlador de eventos de esos controles son todos del tipo "EventHandler" (sin valor de retorno y 2 argumentos : objeto remitente y EventArgs e).

private void UpdateTextLabel(object sender, EventArgs e)
{
    //your original UpdateTextLabel code here
}

button3.Click += UpdateTextLabel;
checkBox1.CheckedChanged += UpdateTextLabel;
numericUpDown1.ValueChanged += UpdateTextLabel;
comboBox1.SelectedIndexChanged += UpdateTextLabel;

Respondido 02 Jul 12, 14:07

Si la lógica dentro de los controladores de eventos suele ser la misma, preferiría este enfoque. - Gene

¡Con seguridad! Puede usar lambdas para lidiar fácilmente con los argumentos no utilizados:

button3.Click += (sender, args) => UpdateTextLabel();
checkBox1.CheckedChanged += (sender, args) => UpdateTextLabel();
numericUpDown1.ValueChanged += (sender, args) => UpdateTextLabel();
comboBox1.SelectedIndexChanged += (sender, args) => UpdateTextLabel();

O como algunos desarrolladores están de moda, si no le importan los argumentos, puede usar guiones bajos para "ignorarlos" por legibilidad:

button3.Click += (_, __) => UpdateTextLabel();
checkBox1.CheckedChanged += (_, __) => UpdateTextLabel();
numericUpDown1.ValueChanged += (_, __) => UpdateTextLabel();
comboBox1.SelectedIndexChanged += (_, __) => UpdateTextLabel();

Como el poderoso Jon Skeet me enseñó una vez, esto es muy superior al esquema de nomenclatura predeterminado de Visual Studio de CONTROLNAME_EVENTNAME, ya que puede leer fácilmente "cuando se hace clic en el botón 3, actualice la etiqueta de texto" o "cuando se cambie el cuadro combinado, actualice el etiqueta de texto". También libera su archivo de código para eliminar un montón de envoltorios de métodos inútiles. :)

EDITAR: si lo tiene repetido 24 veces, eso parece un poco extraño desde el punto de vista del diseño. ... lee de nuevo Oh, maldito. Me perdí los comentarios, quieres ejecutar un código específico al igual que actualizar el cuadro de texto. bueno, tu podría registrar más de un evento:

button3.Click += (_, __) => SubmitForm();
button3.Click += (_, __) => UpdateTextLabel();

El problema con esto, es técnicamente, no se garantiza que los detectores de eventos se activen en orden. Sin embargo, con este caso simple (especialmente si no usa -= y combinar controladores de eventos) debería estar bien para mantener el orden de ejecución. (Supongo que necesita UpdateTextLabel para disparar después de SubmitForm)

O puede mover el UpdateTextLabel llame a su controlador de botón:

button3.Click += (_, __) => SubmitForm();

private void SubmitForm(object sender, EventArgs e)
{
    //do submission stuff
    UpdateTextLabel();
}

Lo que te pone en el mismo barco (aunque con una mejor denominación del método). Tal vez en su lugar deberías mover el UpdateTextLabel en un "reenlace" general para su formulario:

button3.Click += (_, __) => SubmitForm();

private void SubmitForm(object sender, EventArgs e)
{
    //do submission stuff
    Rebind();
}

private void Rebind()
{
    GatherInfo();
    UpdateTextLabel();
    UpdateTitles();
}

De esta manera, si tiene que hacer trabajo adicional además de actualizar una etiqueta de texto, todo su código está llamando a un general Rebind (o como quieras llamarlo) y es más fácil de actualizar.

EDITx2: Me di cuenta, otra opción es usar Programación Orientada a Aspectos. con algo como PostSharp puede adornar métodos para ejecutar código especial que se compila. Estoy 99% seguro de que PostSharp le permite adjuntar eventos (aunque nunca lo he hecho específicamente):

button3.Click += (_, __) => SubmitForm();

[RebindForm]
private void SubmitForm(object sender, EventArgs e)
{
    //do submission stuff
}

[Serializable]
public class RebindFormAttribute : OnMethodBoundaryAspect
{
    public override void OnSuccess( MethodExecutionArgs args )
    {
        MyForm form = args.InstanceTarget as MyForm; //I actually forgot the "InstanceTarget" syntax off the top of my head, but something like that is there
        if (form != null)
        {
            form.Rebind();
        }
    }
}

Entonces, aunque no hacemos una llamada explícita a ningún lugar para Rebind(), el atributo y la Programación Orientada a Aspectos terminan ejecutando ese código adicional OnSuccess allí cada vez que el método se invoca con éxito.

Respondido 02 Jul 12, 14:07

Otra forma de demostrar que no te importan los parámetros es usar métodos anónimos: button3.Click += delegate { UpdateTextLabel(); }; - jon skeet

¿No estoy esencialmente repitiendo mi método la misma cantidad de veces al hacerlo de esta manera? - Sísifo

@JonSkeet Podría... No es del todo una mala manera de hacerlo, especialmente si tiene muchos parámetros. Tendré que recordar eso. Creo que me quedaré con la sintaxis lambda cuando haya pocos parámetros. Gracias. :) - chris sinclair

@Sisyphus Sí, me acabo de dar cuenta de eso. Verifique mi edición y vea si eso ayuda, lo siento. - chris sinclair

Entonces, solo para asegurarme de que entiendo, aún tendría que hacer esto para cada control en mi formulario con el que quiero activar un evento de actualización. ¿Sí? - Sísifo

Sí, no quieres escribir código como este. No es necesario que lo haga, el evento Application.Idle es ideal para actualizar el estado de la interfaz de usuario. Se ejecuta cada vez que Winforms recupera todos los mensajes pendientes de la cola de mensajes. Por lo tanto, está garantizado que se ejecutará después de cualquiera de los eventos a los que esté suscrito actualmente. Haz que se vea así:

    public Form1() {
        InitializeComponent();
        Application.Idle += UpdateTextLabel;
        this.FormClosed += delegate { Application.Idle -= UpdateTextLabel; };
    }

    void UpdateTextLabel(object sender, EventArgs e) {
        // etc..
    }

Respondido 02 Jul 12, 13:07

pero se ejecutaría después de que CADA acción volviera a estar inactiva? Esto suena muy parecido a lo que estaba pensando... habrá que probarlo! - Sísifo

Está bien, esto parece ejecutarse casi constantemente, genial, pero podría ser un poco exagerado... Agregué un pequeño número aleatorio a la etiqueta de actualización y simplemente se vuelve loco hasta que detengo el mouse. ¿Puedo ralentizar eso un poco? - Sísifo

¿Por qué te preocupas por el código que se ejecuta cuando no pasa nada? Podría reiniciar un temporizador en el controlador de eventos Idle, pero no tiene mucho sentido. Use taskmgr.exe, pestaña Procesos y verifique la carga de la CPU en su proceso cuando mueva el mouse. Conseguirlo por encima del 1% sería inusual. - Hans Passant

Siendo bastante nuevo en esto, parece extraño tener la forma "trabajando" y recalculando casi constantemente. Supongo que podría establecer una variable de formulario en reCalculationNeeded = false; y simplemente configúrelo en verdadero para todos los eventos que necesito para hacer el recálculo... pero supongo que eso no es mejor que simplemente escribir el método Actualizar 24 veces... Tengo mucho que aprender.) - Sísifo

Probar y establecer un valor de propiedad solo toma un par de nanosegundos. El mouse es empujado por un humano, informa cambios de posición en un par de milisegundos. Un millón de veces más lento. El único costo real son los controles de repintado. Pero eso solo sucede cuando la propiedad realmente cambia y no lo hace el evento Idle. Nunca optimizar el código que no requiere optimización. - Hans Passant

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.