2013-03-06 13 views
10

Ho riscontrato questo problema con un metodo in C#. Ho creato un metodo che chiama una funzione da una DLL denominata Phone.GetLampMode(); Ora Phone.GetLampMode non restituisce nulla. I dati vengono restituiti in un evento "onGetLampModeResponse". C'è un modo in cui posso aspettare nel mio metodo fino a quando non ottengo i dati dall'evento onGetLampModeResponse?Attendere il metodo interno finché non viene catturato l'evento

public bool checkLamp(int iLamp) 
{ 
    Phone.ButtonIDConstants btn = new Phone.ButtonIDConstants(); 
    btn = Phone.ButtonIDConstants.BUTTON_1; 
    btn += iLamp; 
    Phone.GetLampMode(btn, null); 

    return true; 
} 

private void Phone_OnGetLampModeResponse(object sender, Phone.GetLampModeResponseArgs e) 
{ 
    var test = e.getLampModeList[0].getLampMode.ToString();  
} 
+1

Qual è il secondo parametro di GetLampMode? Fammi indovinare: un oggetto che puoi definire te stesso? E questo oggetto è il 'sender' nel gestore di eventi o all'interno di' e'? EDIT: Sì, si chiama userState. È possibile recuperare questo userState all'interno della variabile 'e' nella funzione di callback. – sinni800

+0

Posso pensare a una brutta soluzione definendo un 'bool' globale che è impostato su' true' da 'OnGetLampModeResponse' e ​​controllato in un ciclo da' checkLamp'. –

+0

@JohnWillemse è abbastanza brutto e non dovrebbe essere fatto poiché esiste il concetto di passare le variabili di stato agli eventi. – sinni800

risposta

9

Una soluzione è quella di utilizzare AutoResetEvent:

public bool checkLamp(int iLamp) 
{ 
    Phone.ButtonIDConstants btn = new Phone.ButtonIDConstants(); 
    btn = Phone.ButtonIDConstants.BUTTON_1; 
    btn += iLamp; 

    AutoResetEvent waitHandle = new AutoResetEvent(false); 

    // Pass waitHandle as user state 
    Phone.GetLampMode(btn, waitHandle); 

    // Wait for event completion 
    waitHandle.WaitOne(); 

    return true; 
} 

private void Phone_OnGetLampModeResponse(object sender, Phone.GetLampModeResponseArgs e) 
{ 
    var test = e.getLampModeList[0].getLampMode.ToString(); 

    // Event handler completed 
    // I guess there is some UserState property in the GetLampModeResponseArgs class 
    ((AutoResetEvent)e.UserState).Set(); 
} 

NOTA: annuncio che si sta utilizzando Phone come classe/variabile statica, si può pensare che si sta sviluppando su Windows Phone ... In tal caso, si noti che l'intero concetto di programmazione WP e asincrono è quello di non bloccare il thread dell'interfaccia utente in modo tale.

+2

Hai appena inserito waitHandle nel contesto globale? Cosa succede se lo esegui più di una volta e rimani completamente bloccato? Come può questa risposta ottenere anche voti positivi? – sinni800

+0

@ sinni800 Buon commento, ma l'OP non ha specificato nulla sul multi-threading. Penso che voglia solo fare qualcosa di sincronizzato da asincrono. Se è effettivamente multi-thread, l'handle di attesa deve essere passato come parametro del metodo. – ken2k

+0

dovrebbe essere sicuramente passato come userState, in QUALSIASI caso. Si rischia di ottenere un filo infilato all'infinito a causa di cose così morbose come "condizioni di gara". – sinni800

0

Sembra che il modello esistente sia vicino al modello asincrono basato sugli eventi (EAP). Si consiglia di guardare l'articolo Interop with Other Asynchronous Patterns and Types che descrive come convertire un tale modello nel nuovo modello asincrono basato su attività (TAP).

volta che avete un Task (o Task<T>, si può semplicemente Wait per esso

+0

Sì, le parole chiave Async sarebbero perfette .. – sinni800

2

Puoi avvolgere il gestore in un metodo asincrono, che dovrebbe essere simile a questa (non testato):.

public async Task<bool> checkLamp(int iLamp) 
{ 
    Phone.ButtonIDConstants btn = new Phone.ButtonIDConstants(); 
    btn = Phone.ButtonIDConstants.BUTTON_1; 
    btn += iLamp; 

    var tcs = new TaskCompletionSource<bool>(); 
    var handler = (sender, e) => { 
     Phone.OnGetLampModeResponse -= handler; 
     var test = e.getLampModeList[0].getLampMode.ToString(); 
     tcs.SetResult(true); 
    }; 
    Phone.OnGetLampModeResponse += handler; 

    Phone.GetLampMode(btn, null); 

    return tcs.Task; 
} 

Nel vostro metodo di chiamata, si può scrivere:

Questo ha il vantaggio che il vostro doe interfaccia utente s non si blocca mentre il processo è in attesa della risposta.

Ecco un post di blog su questo problema. Si noti che è necessario Framework 4.5.

Problemi correlati