2012-08-12 33 views

Respuesta

33

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.CurrentDispatcheren 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.

+0

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"? –

+1

@RogerWillcocks: Nunca me pasó a mí. Da un ejemplo completo reproduciendo esto ... –

+0

Application.Current.Dispatcher.Invoke (new Action (() => textBox.Text = "Test")); Funcionó a la perfección! ¡Gracias! –

0

Eso serían varios cientos de líneas de código, para algo que "descubrí".

Pero el resumen es:

App_OnStartup generar un subproceso de fondo

en la devolución de llamada,

llamada

Application.Current.MainWindow.Dispatcher.CheckAccess() - Obtiene la excepción Application.Current.Dispatcher.CheckAccess() no hace

+1

El problema es el paso 'Current.MainWindow', no' MainWindow.Dispatcher', así que sí, eso no es lo que sugeriría ... –

+0

Como me di cuenta, pero dado que MainWindow y Dispatcher no son nulos, se esperaría que un método destinado a decirle si el acceso de subprocesos cruzados es seguro no arrojaría una excepción cruzada –

0

tengo un objeto detector udp que se comunica a través de eventos donde el método/devoluciones de llamada son + = 'ed en mi mainWindow wpf .cs archivo.

Las funciones de controlador de eventos son llamados con parámetros, uno de ellos el mensaje que desee mostrar en un cuadro de lista en las mainWindow.cs

Uso de la información en este hilo por H. B. encima; He añadido, probado y manejado el desgarre en WPF en mi devolución de llamada eventhandler usando el siguiente código, pero yo uso un mensaje real no es modificable uno:

listBox1.Dispatcher.Invoke(new Action(() => listBox1.Items.Add("MessageHere"))); 

ACTUALIZACIÓN:

Este es mejor porque puedes poner más cosas en la función anónima.

listBox1.Dispatcher.Invoke((Action)delegate 
{ 
    listBox1.Items.Add(e.ReaderMessage); 
}); 
Cuestiones relacionadas