2010-11-18 16 views
50

Diciamo, voglio passare alcuni dati extra quando si assegna un gestore di eventi. Considera il seguente codice:C# passa parametri aggiuntivi a un gestore di eventi?

private void setup(string someData) 
{ 
    Object.assignHandler(evHandler); 
} 

public void evHandler(Object sender) 
{ 
    // need someData here!!! 
} 

Come potrei fare per ottenere alcuni dati nel mio metodo evHandler?

+0

ho una soluzione più standard in questa domanda, prima risposta http://stackoverflow.com/questions/14058412/passing-parameter-to-an-event-handler/14058441#14058441 –

risposta

49
private void setup(string someData) 
{ 
    Object.assignHandler((sender) => evHandler(sender,someData)); 
} 
public void evHandler(Object sender, string someData) 
{ 
    // need someData here!!! 
} 
+1

Questa è un'ottima soluzione, ma cosa succederebbe se EventHandler avesse già TArgs. Come + = new EventHandler (evHandler)? – Roast

+0

Ciao @Lily, non è del tutto chiaro cosa stai chiedendo. Potrebbe essere meglio pubblicare una domanda (piuttosto che un commento) con un po 'più di dettaglio e un codice per dimostrare cosa stai cercando di fare. – spender

+1

Grazie, questo ha risolto un problema che stavo avendo, ma sono nuovo di C# quindi ti dispiacerebbe spiegare che cosa è questo costrutto linguaggio o dandomi una parola chiave su google per una spiegazione? –

0

Ebbene, il metodo più semplice id per fare someData una variabile membro in questo modo:

public class MyClass 
{ 
    private string _eventData; 

    private void setup(string someData) 
    { 
     _eventData = someData; 
     Object.assignHandler(evHandler); 
    } 

    public void evHandler() 
    { 
     // do something with _eventData here 
    } 
} 

non sono sicuro che è il modo migliore per farlo, ma in realtà dipende dal tipo di evento, l'oggetto, ecc

+1

stava pensando a questo metodo, tuttavia l'installazione può essere chiamata più volte con diversi dataData. Questi dati dovrebbero essere unici per ogni gestore. –

+0

In questo caso, la soluzione di Spender o Marc è molto migliore – CodingGorilla

17

variabili catturate:

private void setup(string someData) 
{ 
    Object.assignHandler((sender,args) => { 
     evHandler(sender, someData); 
    }); 
} 

public void evHandler(Object sender, string someData) 
{ 
    // use someData here 
} 

Or (C# 2.0 alternativi):

Object.assignHandler((EventHandler)delegate(object sender,EventArgs args) { 
     evHandler(sender, someData); 
    }); 
+2

è la variabile catturata === chiusura? – Matt

+2

@Matt - sì, le variabili catturate sono chiusure lessicali. –

+0

Per chiarire, la prima soluzione non è valida per C# .NET 2.0? –

2

si può provare a fare questo:

string yourObject; 

theClassWithTheEvent.myEvent += (sender, model) => 
{ 
yourObject = "somthing"; 
} 
0

è possibile creare un oggetto personalizzato con proprietà aggiuntive sulla base di oggetto:

class CustomObject : Object 
{ 
    public string SomeData; 
} 

private void setup(string someData) 
{ 
    CustomObject customObject = new CustomObject { SomeData = someData }; 
    CustomObject.assignHandler(evHandler); 
} 

public void evHandler(Object sender) 
{ 
    string someData = ((CustomObject)sender).SomeData; 
} 

Se i dati non devono essere modificati più dopo l'inizializzazione, potresti anche aggiungere un costruttore personalizzato, per esempio.

14

Ho avuto difficoltà a capire l'esempio di @ spender in particolare con: Object.assignHandler((sender) => evHandler(sender,someData)); perché non esiste una cosa come Object.assignHandler in senso letterale. Così ho fatto un po 'di più su Google e ho trovato this example. La risposta di Peter Duniho era quello che scattò nella mia testa (questo non è il mio lavoro):

snip

L'approccio comune è quello di utilizzare un metodo anonimo con un gestore di eventi che ha il vostro modificata firma. Per esempio:

void Onbutton_click(object sender, EventArgs e, int i) { ... } 

button.Click += delegate(object sender, EventArgs e) 
{ Onbutton_click(sender, e, 172); }; 

Naturalmente, non c'è bisogno di passare in 172, o anche fare il terzo parametro un int. :)

/snip

Utilizzando questo esempio sono stato in grado di passare in due personalizzato ComboBoxItem oggetti a un Timer.Elapsed evento utilizzando lambda notazione:

simulatorTimer.Elapsed += 
(sender, e) => onTimedEvent(sender, e, 
(ComboBoxItem) cbPressureSetting.SelectedItem, 
(ComboBoxItem) cbTemperatureSetting.SelectedItem); 

e poi in esso del conduttore:

static void onTimedEvent(object sender, EventArgs e, ComboBoxItem pressure, ComboBoxItem temperature) 
    { 
     Console.WriteLine("Requested pressure: {0} PSIA\nRequested temperature: {1}° C", pressure, temperature); 
    } 

Questo non è un nuovo codice dagli esempi sopra, ma dimostra devo interpretarli Spero che qualcuno come me trovi utile & così da non passare ore a cercare di capire il concetto come ho fatto io.

Questo codice funziona nel mio progetto (ad eccezione di un'eccezione non thread-safe con gli oggetti ComboBoxItem che non credo cambia come funziona l'esempio). Lo sto capendo adesso.

0

Ecco la mia soluzione a una linea che passa parametri aggiuntivi a un gestore di timer.

private void OnFailed(uint errorCode, string message) 
{ 
    ThreadPoolTimer.CreateTimer((timer) => { 
    UI.ErrorMessage = string.Format("Error: 0x{0:X} {1}", errorCode, message); 
    }, System.TimeSpan.FromMilliseconds(100)); 
} 
0

mia domanda che era simile è stato segnato un duplicato così abbiamo pensato che mi piacerebbe aggiungere una risposta qui dal momento che non mi lascia sulla mia domanda.

class Program 
    { 
     delegate void ComponentEventHandler(params dynamic[] args); 

     event ComponentEventHandler onTest; 

     static void Main(string[] args) 
     { 
      Program prg = new Program(); 

      // can be bound to event and called that way 
      prg.onTest += prg.Test; 
      prg.onTest.Invoke("What", 5, 12.0); 

      Console.ReadKey(); 
     } 

     public void Test(params dynamic[] values) 
     { 
      // assign our params to variables 
      string name = values[0]; 
      int age = values[1]; 
      double value = values[2]; 

      Console.WriteLine(name); 
      Console.WriteLine(age); 
      Console.WriteLine(value); 
     } 
    } 
Problemi correlati