wpf
Afinidad de hilos que accede a los elementos de la interfaz de usuario
Buscar..
Acceder a un elemento UI desde dentro de una tarea
Todos los elementos de la interfaz de usuario creados y residen en el hilo principal de un programa. Acceder a estos desde otro hilo está prohibido por el tiempo de ejecución de .net framework. Básicamente, se debe a que todos los elementos de la interfaz de usuario son recursos sensibles a los subprocesos y el acceso a un recurso en un entorno de subprocesos múltiples debe ser seguro para subprocesos. Si se permite este acceso a objetos de subprocesos cruzados, la consistencia se vería afectada en primer lugar.
Considere este escenario:
Tenemos un cálculo que sucede dentro de una tarea. Las tareas se ejecutan en otro hilo que el hilo principal. Mientras el cálculo continúa, necesitamos actualizar una barra de progreso. Para hacer esto:
//Prepare the action
Action taskAction = new Action( () => {
int progress = 0;
Action invokeAction = new Action( () => { progressBar.Value = progress; });
while (progress <= 100) {
progress = CalculateSomething();
progressBar.Dispatcher.Invoke( invokeAction );
}
} );
//After .net 4.5
Task.Run( taskAction );
//Before .net 4.5
Task.Factory.StartNew( taskAction ,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
Cada elemento de la interfaz de usuario tiene un objeto Dispatcher que proviene de su ancestro DispatcherObject
(dentro del espacio de nombres System.Windows.Threading
). Dispatcher ejecuta el delegado especificado de forma sincrónica en la prioridad especificada en el subproceso en el que está asociado el Dispatcher. Dado que la ejecución está sincronizada, la tarea del que llama debe esperar su resultado. Esto nos da la oportunidad de utilizar el int progress
también dentro de un delegado de despacho.
Es posible que queramos actualizar un elemento de la interfaz de usuario de forma asíncrona y luego invokeAction
cambios de definición de invokeAction
:
//Prepare the action
Action taskAction = new Action( () => {
int progress = 0;
Action<int> invokeAction = new Action<int>( (i) => { progressBar.Value = i; } )
while (progress <= 100) {
progress = CalculateSomething();
progressBar.Dispatcher.BeginInvoke(
invokeAction,
progress );
}
} );
//After .net 4.5
Task.Run( taskAction );
//Before .net 4.5
Task.Factory.StartNew( taskAction ,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
Esta vez empaquetamos el int progress
y lo usamos como un parámetro para delegar.