9

In .NET, Windows 8 e Windows Phone 7 Ho codice simile a questo:Portable libreria di classi equivalente di Dispatcher.Invoke o Dispatcher.RunAsync

public static void InvokeIfRequired(this Dispatcher dispatcher, Action action) 
{ 
    if (dispatcher.CheckAccess()) 
    { 
     action(); 
    } 
    else 
    { 
     dispatcher.Invoke(action); 
    } 
} 

Come potrei fare qualcosa nella libreria di classi portatile? Sarebbe bello avere una sola implementazione agnostica della piattaforma. La mia idea è di usare la TPL che non è disponibile in WP7 ma sicuramente lo sarà presto.

L'unica cosa di cui non sono sicuro è quali sarebbero le implicazioni in termini di prestazioni. Forse farò dei test.

risposta

2

Con l'avvento del TPL. Ho trovato una versione leggermente migliorata della risposta accettata che restituisce un'attività e può essere attesa utilizzando il nuovo async e attendere le parole chiave.

public Task RunAsync(Action action) 
{ 
    TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>(); 

    if (this.synchronizationContext == SynchronizationContext.Current) 
    { 
     try 
     { 
      action(); 
      taskCompletionSource.SetResult(null); 
     } 
     catch (Exception exception) 
     { 
      taskCompletionSource.SetException(exception); 
     } 
    } 
    else 
    { 
     // Run the action asyncronously. The Send method can be used to run syncronously. 
     this.synchronizationContext.Post(
      (obj) => 
      { 
       try 
       { 
        action(); 
        taskCompletionSource.SetResult(null); 
       } 
       catch (Exception exception) 
       { 
        taskCompletionSource.SetException(exception); 
       } 
      }, 
      null); 
    } 

    return taskCompletionSource.Task; 
} 
+2

Nice. Sembra che tu abbia creato un corso, ma che abbia pubblicato il metodo solo in modo tale che una nota (forse ovvia) per gli altri. this.synchronizationContext deve essere assegnato nel thread in cui si desidera eseguire l'azione prima di chiamare il metodo. In realtà ho modificato sopra un po 'e creato un'estensione: public Task RunAsync (questo contesto SynchronizationContext, Action action). Ora è più simile alla risposta originale in quanto può stare da solo. Il meglio di entrambe le risposte. :) – Wes

13

È possibile utilizzare il metodo SynchronizationContext.Post o Invia. È portatile e quando si utilizza una struttura dell'interfaccia utente con un dispatcher, il contesto di sincronizzazione corrente delegherà il lavoro al Dispatcher.

In particolare, è possibile utilizzare il seguente codice:

void InvokeIfRequired(this SynchroniationContext context, Action action) 
{ 
    if (SynchroniationContext.Current == context) 
    { 
     action(); 
    } 
    else 
    { 
     context.Send(action) // send = synchronously 
     // context.Post(action) - post is asynchronous. 
    } 
} 
+0

Bello. Come creeresti il ​​metodo di estensione che uso sopra per il dispatcher. In particolare, come si controlla se si sta già eseguendo il thread dell'interfaccia utente invece di fare dispatcher.CheckAccess(). –

+0

È inoltre possibile postare l'equatore di BeginInvoke e inviare l'equivoco di Invoke? –

+1

Non è necessario controllare prima di pubblicare. Post fa già i controlli adeguati. –