Dependiendo de la situación, hay varias opciones:
Acceso a un control desde otro hilo
por ejemplo actualizar un TextBlock con información de progreso.
Data Binding:
En este caso lo más fácil que puede hacer es evitar la interacción directa con el control. Puede simplemente bind la propiedad que desea acceder o modificar a un objeto cuya clase implementsINotifyPropertyChanged
y luego establecer la propiedad en ese objeto en su lugar. El marco se encargará del resto por ti. (En general, rara vez debería necesitar interactuar directamente con elementos UI, casi siempre puede enlazar las propiedades respectivas y trabajar con la fuente de enlace; un caso en el que puede ser necesario el control directo es la creación de controles.)
There son algunos casos en los que los datos de unión sola no es suficiente, por ejemplo, al intentar modificar una cota ObservableCollection<T>
, para ello es necesario ...
Dispatching:
puede enviar el código para acceder a la rosca Poseer el objeto, esto se puede hacer llamando al Invoke
o BeginInvoke
en el Dispatcher
que posee el objeto al que se accede (obtener este Dispatcher
es posible en otra secuencia).
p. Ej.
new Thread(ThisThreadStart).Start();
void ThisThreadStart()
{
textBlock.Dispatcher.Invoke(new Action(() => textBlock.Text = "Test"));
}
Si no está claro en qué hilo se ejecuta un método que puede utilizar Dispatcher.CheckAccess
a su expedición o ejecutar una acción directa.
p. Ej.
void Update()
{
Action action =() => myTextBlock.Text = "Test";
var dispatcher = myTextBlock.Dispatcher;
if (dispatcher.CheckAccess())
action();
else
dispatcher.Invoke(action);
}
Si un objeto no es un DispatcherObject
y todavía necesita el Dispatcher
asociado puede utilizar Dispatcher.CurrentDispatcher
en el hilo de crear el objeto (de modo de hacer esto en el método de ser ejecutado por un hilo no le hará ningún bueno). Por comodidad, ya que normalmente crea objetos en la hebra de interfaz de usuario principal de la aplicación; puede obtener el hilo Dispatcher
desde cualquier lugar usando Application.Current.Dispatcher
.
casos especiales:
BackgroundWorker
mover cualquier control de acceso a ProgressChanged
ya que se produce en el subproceso que creó la instancia (que debe ser, por supuesto la interfaz de usuario-hilo)
Temporizadores
En WPF puede usar el DispatcherTimer
por comodidad, hace el envío para que se invoque cualquier código en Tick
en el despachador asociado. Si puede delegar el envío al sistema de enlace de datos, por supuesto también puede usar un temporizador normal.
Usted puede leer más acerca de cómo funciona la cola Dispatcher
y WPF enhebrar en general on MSDN.
acceso a un objeto creado en otro hilo
por ejemplo cargando una imagen en el fondo.
Si el objeto en cuestión no es Freezable
se deben, en general, simplemente evitar la creación en otro hilo o restringir el acceso al hilo creador. Si es Freezable
, solo necesita llamar al Freeze
para que sea accesible a otros hilos.
Acceso a un objeto de datos de otro hilo
Esto es, el tipo cuya instancia está siendo actualizado es fácil de código. Si se lanza una excepción, esta situación probablemente se produjo por alguien que usa DependencyObject
como tipo de base para una clase de datos.
Esta situación es la misma que accediendo a un control y se pueden aplicar los mismos enfoques, pero por lo general se debe evitar en primer lugar. Por supuesto, esto permite notificaciones simples de cambio de propiedad a través de dependency properties y esas propiedades también pueden vincularse, pero a menudo esto no vale la pena abandonar la independencia de subprocesos. Puede obtener notificaciones de cambio desde INotifyPropertyChanged
y el sistema de enlace en WPF es inherentemente asimétrico, siempre hay una propiedad que está vinculada (destino) y algo que es la fuente de esta vinculación. Por lo general, la interfaz de usuario es el objetivo y los datos son la fuente, lo que significa que solo los componentes de la interfaz de usuario deben tener propiedades de dependencia.
Así que aquí hay una pregunta tonta. ¿Qué haces cuando Dispatcher.CheckAccess() arroja "El hilo de llamada no puede acceder a este objeto porque lo posee un hilo diferente"? –
@RogerWillcocks: Nunca me pasó a mí. Da un ejemplo completo reproduciendo esto ... –
Application.Current.Dispatcher.Invoke (new Action (() => textBox.Text = "Test")); Funcionó a la perfección! ¡Gracias! –