c# - thread - En WPF, ¿cuál es el equivalente de Suspend/ResumeLayout() y BackgroundWorker() de Windows Forms?
invokerequired c# (3)
Si estoy en una función en el código subyacente, y deseo implementar la visualización de un "Cargando ..." en la barra de estado, lo siguiente tiene sentido, pero como sabemos por WinForms es un NoNo:
StatusBarMessageText.Text = "Loading Configuration Settings...";
LoadSettingsGridData();
StatusBarMessageText.Text = "Done";
Lo que todos ahora de WinForms Capítulo 1 clase 101, es que el formulario no mostrará los cambios al usuario hasta después de que se complete la función completa ... lo que significa que el mensaje "Cargando" nunca se mostrará al usuario. El siguiente código es necesario.
Form1.SuspendLayout();
StatusBarMessageText.Text = "Loading Configuration Settings...";
Form1.ResumeLayout();
LoadSettingsGridData();
Form1.SuspendLayout();
StatusBarMessageText.Text = "Done";
Form1.ResumeLayout();
¿Cuál es la mejor práctica para tratar este tema fundamental en WPF?
La forma más fácil de hacer que esto funcione es agregar LoadSettingsGridData a la cola del despachador. Si configura DispatcherPriority de la operación lo suficientemente bajo como para que ocurran las operaciones de diseño, estará listo para continuar.
StatusBarMessageText.Text = "Loading Configuration Settings...";
this.Dispatcher.BeginInvoke(new Action(LoadSettingsGridData), DispatcherPriority.Render);
this.Dispatcher.BeginInvoke(new Action(() => StatusBarMessageText.Text = "Done"), DispatcherPriority.Render);
Al leer el artículo de Shawn Wildermuth WPF Threads: Cree aplicaciones más receptivas con The Dispatcher .
Me encontré con lo siguiente, que dice que puedes usar el Background Worker como lo harías en WindowsForms. De lujo que:
BackgroundWorker Ahora que tiene una idea de cómo funciona el Dispatcher, es posible que se sorprenda al saber que no encontrará uso en la mayoría de los casos. En Windows Forms 2.0, Microsoft introdujo una clase para el manejo de subprocesos no UI para simplificar el modelo de desarrollo para los desarrolladores de la interfaz de usuario. Esta clase se llama BackgroundWorker. La Figura 7 muestra el uso típico de la clase BackgroundWorker.
Figura 7 Usando un BackgroundWorker en WPF
BackgroundWorker _backgroundWorker = new BackgroundWorker(); ... // Set up the Background Worker Events _backgroundWorker.DoWork += _backgroundWorker_DoWork; backgroundWorker.RunWorkerCompleted += _backgroundWorker_RunWorkerCompleted; // Run the Background Worker _backgroundWorker.RunWorkerAsync(5000); ... // Worker Method void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { // Do something } // Completed Method void _backgroundWorker_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) { statusText.Text = "Cancelled"; } else if (e.Error != null) { statusText.Text = "Exception Thrown"; } else { statusText.Text = "Completed"; } }
El componente BackgroundWorker funciona bien con WPF porque debajo de las cubiertas utiliza la clase AsyncOperationManager, que a su vez usa la clase SynchronizationContext para tratar con la sincronización. En Windows Forms, AsyncOperationManager distribuye una clase WindowsFormsSynchronizationContext que deriva de la clase SynchronizationContext. Del mismo modo, en ASP.NET funciona con una derivación diferente de SynchronizationContext llamada AspNetSynchronizationContext. Estas clases derivadas de SynchronizationContext saben cómo manejar la sincronización entre hilos de la invocación del método.
En WPF, este modelo se amplía con una clase DispatcherSynchronizationContext. Al utilizar BackgroundWorker, el Dispatcher se utiliza automáticamente para invocar llamadas a métodos de hilos cruzados. La buena noticia es que, dado que probablemente ya esté familiarizado con este patrón común, puede continuar utilizando BackgroundWorker en sus nuevos proyectos de WPF.
Mejor y más simple:
using(var d = Dispatcher.DisableProcessing())
{
/* your work... Use dispacher.begininvoke... */
}
O
IDisposable d;
Try
{
d = Dispatcher.DisableProcessing();
/* your work... Use dispacher.begininvoke... */
} Finally {
d.Dispose();
}