c# .net wpf multithreading dispatcher

dispatcher.invoke c#



El subproceso que llama no puede acceder a este objeto porque un subproceso diferente lo posee.WPF (6)

Comencé un subproceso que no es de la interfaz de usuario y dentro de este subproceso también inicié un subproceso de la interfaz de usuario. Así que mi requisito es como ejecutar un subproceso de interfaz de usuario dentro de un subproceso que no es de interfaz de usuario. Al manejar este escenario obtuve la siguiente excepción. "Excepción: el subproceso que realiza la llamada no puede acceder a este objeto porque otro subproceso lo posee".

En este caso, utilicé el método Dispatcher.Invoke del elemento UI de la siguiente manera y funcionó bien.

if (m_contextWindow == null) { System.Threading.Thread newWindowThread = new System.Threading.Thread(new ThreadStart( () => { // Create and show the Window m_contextWindow = new ContextWindow(); m_contextWindow.DataContext = this; m_contextWindow.Show(); // Start the Dispatcher Processing System.Windows.Threading.Dispatcher.Run(); })); // Set the apartment state newWindowThread.SetApartmentState(ApartmentState.STA); // Make the thread a background thread newWindowThread.IsBackground = true; // Start the thread newWindowThread.Start(); } else { this.m_contextWindow.Dispatcher.Invoke(new ThreadStart(() => { m_contextWindow.DataContext = this; if (m_contextWindow.Visibility == System.Windows.Visibility.Collapsed || m_contextWindow.Visibility == System.Windows.Visibility.Hidden) m_contextWindow.Visibility = System.Windows.Visibility.Visible; })); }

Cada vez que actualizo una etiqueta, recibí este error: el subproceso que realiza la llamada no puede acceder a este objeto porque otro subproceso lo posee. Intenté invocar pero ha fallado. Estoy usando el formulario WPF.

delegate void lostfocs(string st); private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Thread t = new Thread(modi); t.Start(); } void modi() { try { label1.Content = "df"; } catch { lostfocs ld = new lostfocs(up); // ld.Invoke("df"); object obj=new object(); ld.Invoke("sdaf"); } } void up(string st) { label1.Content = st; }


Puedes usar Dispatcher para esto. Su código se convierte en ...

private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() => { try { label1.Content = "df"; } catch { lostfocs ld = new lostfocs(up); // ld.Invoke("df"); object obj=new object(); ld.Invoke("sdaf"); } } ));


Utilice Dispatcher.Invoke Método.

Ejecuta el delegado especificado de forma síncrona en el subproceso con el que está asociado Dispatcher.

también

En WPF, solo el hilo que creó un DispatcherObject puede acceder a ese objeto. Por ejemplo, un hilo de fondo que se separa del hilo principal de la interfaz de usuario no puede actualizar el contenido de un botón que se creó en el hilo de la interfaz de usuario . Para que el subproceso de fondo acceda a la propiedad Contenido del botón, el subproceso de fondo debe delegar el trabajo en el Distribuidor asociado al subproceso de la interfaz de usuario. Esto se logra usando Invoke o BeginInvoke. La invocación es sincrónica y BeginInvoke es asíncrona. La operación se agrega a la cola de eventos del Dispatcher en la DispatcherPriority especificada.

Recibirá el error porque su etiqueta se crea en el subproceso de la interfaz de usuario y está intentando modificar su contenido a través de otro subproceso. Aquí es donde necesitarías Dispatcher.Invoke.

Echa un vistazo a este artículo Los hilos de WPF crean aplicaciones más sensibles con The Dispatcher


Varias sugerencias para usar BeginInvoke, pero ninguna mención de EndInvoke. Una buena práctica es que ''todos los BeginInvoke tienen un EndInvoke que coincida'' y, ciertamente, debe haber alguna protección contra las condiciones de la carrera (Piensa: ¿qué sucede con los múltiples BeginInvoke de código pero ninguno ha terminado de procesarse todavía?)

Es fácil de olvidar, y he visto este error (y, sí, es un error) tanto en los ejemplos de MSDN como en los libros publicados en WinForms.


utilizar Dispatcher.Invoke

Ejemplo

void modi() { if(!Dispatcher.CheckAccess()) { Dispatcher.Invoke( ()=>label1.Content = "df",DispatcherPriority.Normal); } else { label1.Content = "df"; } }


private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() => { try { label1.Content = "df"; } catch { lostfocs ld = new lostfocs(up); object obj = new object(); ld.Invoke("sdaf"); } })); }