2012-03-02 6 views
16

Desde el Windows 8 Vista previa del consumidor fue lanzado hace unos días, estoy trabajando en el nuevo WinRT (para aplicaciones Metro) en C# y me había portado mi ser escrita de clase IRC a la nueva roscado y redes.actualización de la interfaz de usuario a partir de hilos en WinRT

El problema es: Mi clase está en ejecución un subproceso para recibir mensajes desde el servidor. Si esto sucede, el hilo está realizando un análisis sintáctico y luego activando un evento para informar a la aplicación sobre esto. La función suscrita entonces 'debería' actualizar la IU (un bloque de texto).

Este es el problema, el hilo no puede actualizar la interfaz de usuario y el método invocador que ha trabajado con .NET 4.0 no parece ser posible nunca más. ¿Existe una nueva solución para esto o una mejor manera de actualizar la UI? Si trato de actualizar la interfaz de usuario del suscriptor de eventos voy a conseguir este Exception:

La aplicación llama una interfaz que se marshalled para un hilo diferente (Excepción de HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

+0

Esto es por diseño. Los hilos cuestan energía de la batería. El nuevo estilo para IO asíncrono es especificando continuaciones. Hay algo de cobertura (tutoriales vidoes) sobre esto en http://channel9.msdn.com. –

+0

Pensándolo bien, podría ser que BackgroundWorker todavía funciona, que es más como un hilo, y también tiene cálculo de referencias (puede enviar actualizaciones de progreso a hilo de interfaz de usuario). –

Respuesta

27

La forma preferida para tratar con esto en WinRT (y C# 5 en general) es utilizar async-await:

private async void Button_Click(object sender, RoutedEventArgs e) 
{ 
    string text = await Task.Run(() => Compute()); 
    this.TextBlock.Text = text; 
} 

Aquí, el método Compute() se ejecutará en un subproceso en segundo plano y cuando termine, el resto del método se ejecutará en el subproceso de la interfaz de usuario. Mientras tanto, el hilo de UI puede hacer lo que necesite (como procesar otros eventos).

Pero si usted no quiere o no puede usar async, puede utilizar Dispatcher, de una manera similar (aunque diferente) como en WPF:

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    Task.Run(() => Compute()); 
} 

private void Compute() 
{ 
    // perform computation here 

    Dispatcher.Invoke(CoreDispatcherPriority.Normal, ShowText, this, resultString); 
} 

private void ShowText(object sender, InvokedHandlerArgs e) 
{ 
    this.TextBlock.Text = (string)e.Context; 
} 
+0

muchas gracias, su segunda idea se ha resuelto por mí sin tener que reescribir toda mi clase :), sólo algunos pequeños reemplazos con su fragmentos de código – Suchiman

+0

Para el segundo ejemplo, recomiendo el uso de un lambda en lugar de un método ShowText - permite usted para evitar el "e.Context". Así que Dispatcher.Invoke (CoreDispatcherPriority.Normal, (s, e) => {this.TextBlock.Text = resultString}, esto, nulo); –

+0

¿Qué pasa si el código no está en una página? ¿Cómo podemos obtener un despachador de BG thread? – Grigory

8

Aquí es una manera más fácil de hacer creo!

primera captura la interfaz de usuario SyncronizationContext con lo siguiente:

var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext(); 

ejecutar su operación de llamada del servidor o cualquier otra operación subproceso de fondo que necesita:

Task serverTask= Task.Run(()=> { /* DoWorkHere(); */}); 

Después, realice la operación de la interfaz de usuario en el UISyncContext se capturado en el primer paso:

Task uiTask= serverTask.ContinueWith((t)=>{TextBlockName.Text="your value"; }, UISyncContext); 
+1

Entonces, ¿es cierto que la respuesta de WINRT a "¿cómo obtengo el contexto de la interfaz de usuario a partir de un hilo de fondo aleatorio?" parece no tener una respuesta simple que no sea modificar todas sus interfaces para pasar en un contexto de interfaz de usuario? La respuesta anterior de Deeb parece funcionar si su objeto de hilo de fondo se crea a partir del hilo de la interfaz de usuario (y, por lo tanto, puede capturar UISyncContext en el constructor). Pero, ¿y si NO se ha creado en el hilo de UI? ¿Qué es lo que me estoy perdiendo, y por qué no hay una forma de muerte cerebral para obtener de manera confiable el contexto de la interfaz de usuario a partir de cualquier hilo de fondo aleatorio? –

+1

No funciona para mí. Obtengo una excepción InvalidOp: 'El SynchronizationContext actual no se puede usar como TaskScheduler. Estoy desarrollando para MS Surface en Win SDK 8 – Howie

Cuestiones relacionadas