¿Qué soluciones tengo si deseo evitar que la UI se congele mientras deserializo una gran cantidad de elementos de UI en WPF? Me llegan errores al quejarse de que los objetos pertenecen a la UI Thread cuando intento cargarlos en otro hilo. Entonces, ¿qué opciones tengo para evitar el error de Vista "Programa que no responde" mientras estoy cargando mis datos de UI? ¿Puedo confiar en una solución de subproceso único o me falta algo con respecto a tal vez múltiples subprocesos de UI?Evite que la IU se congele sin hilos adicionales
Respuesta
Si solo usa un único hilo, la IU se congelará mientras realiza cualquier procesamiento.
Si utiliza un subproceso BackgroundWorker tendrá más control sobre lo que ocurre & cuando.
Para actualizar la interfaz de usuario necesita usar Dispatcher.Invoke
desde el hilo de fondo para ordenar la llamada a través del límite del hilo.
Dispatcher.Invoke(DispatcherPriority.Background,
new Action(() => this.TextBlock.Text = "Processing");
fijas que se pueden hacer de su procesamiento largo en un hilo separado, pero cuando haya terminado usted tiene que sincronizar con el hilo de interfaz de usuario llamando Dispatcher.BeginInvoke(your_UI_action_here)
Recomendaciones del blog OldNewThing.
Lo mejor es ir por la ruta de subprocesos, tener un subproceso de GUI y generar la carga de trabajo en otro subproceso que, cuando finalice los informes en el subproceso de la GUI principal, se complete. La razón de esto es porque no entrarás en problemas con la interfaz GUI.
So One GUI Thread Muchos hilos de trabajo que hacen el trabajo.
Si alguno de sus subprocesos se cuelga, el usuario está en control directo sobre su aplicación, puede cerrar el hilo sin afectar su experiencia con la interfaz de la aplicación. Esto lo hará feliz porque su usuario se sentirá en control además de él constantemente, haga clic en el BOTÓN DETENER Y NO DEJE DE BÚSQUEDA.
Pruebe freezing su UIElements. Los objetos congelados se pueden pasar entre subprocesos sin encontrar una InvalidOperationException, por lo que los deserializará & congélelos en un subproceso de fondo antes de usarlos en su subproceso de interfaz de usuario.
Como alternativa, considere enviar de nuevo las deserializaciones individuales al subproceso UI con prioridad de fondo. Esto no es óptimo, ya que el hilo de la interfaz de usuario todavía tiene que hacer todo el trabajo para deserializar estos objetos y se agregan algunos gastos indirectos al enviarlos como tareas individuales, pero al menos no se bloqueará la interfaz de usuario: eventos de mayor prioridad como entrada podrá intercalarse con su trabajo de deserialización de menor prioridad.
Esto solo funciona para freezables y los elementos de UI no son freezables. Entonces, si solo está hablando de crear geometría, pinceles, etc., esto funciona, pero si está hablando de construir elementos de interfaz de usuario (es decir, clase visual y hasta la cadena de herencia) no funciona. –
Vaya, buen punto en UIElement no ser freezable. –
Here is a wonderful blog posting from Dwane Need que analiza todas las opciones disponibles para trabajar con elementos de IU entre múltiples hilos.
Realmente no has dado suficientes detalles para dar una buena receta. Por ejemplo, ¿por qué está creando elementos UI usted mismo en vez de usar databinding? Puede que tenga una buena razón, pero sin más detalles es difícil dar un buen consejo. Como otro ejemplo de detalle que sería útil, ¿busca construir jerarquías complejas de control profundamente anidadas para cada dato o simplemente necesita dibujar una forma simple?
Puede girar el flujo de control sobre su cabeza usando DispatcherFrames, permitiendo que la deserialización proceda en el hilo de la interfaz de usuario en el fondo.
Primero necesita una forma de obtener control periódicamente durante la deserialización. No importa qué deserializador esté utilizando, tendrá que invocar conjuntos de propiedades en sus objetos, por lo que normalmente puede agregar código a los establecedores de propiedades. Alternativamente, puedes modificar el deserializador. En cualquier caso, asegúrese de que su código se llama la frecuencia suficiente
Cada vez que reciba el control, todo lo que tiene que hacer es:
- Crear un DispatcherFrame
- cola de un evento para el despachador usando BeginInvoke que Continuar conjuntos = false en el marco de
- uso PushFrame para iniciar el bastidor se ejecuta en el Dispatcher
Además, cuando se llama a sí mismo el deserializer asegúrese años u hacer desde Dispatcher.BeginInvoke, o que su código de llamada no se mantiene ningún bloqueo etc.
es como se vería aquí:
public partial class MyWindow
{
SomeDeserializer _deserializer = new SomeDeserializer();
byte[] _sourceData;
object _deserializedObject;
...
void LoadButton_Click(...)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
_deserializedObject = _deserializer.DeserializeObject(_sourceData);
}));
}
}
public class OneOfTheObjectsBeingDeserializedFrequently
{
...
public string SomePropertyThatIsFrequentlySet
{
get { ... }
set { ...; BackgroundThreadingSolution.DoEvents(); }
}
}
public class BackgroundThreadingSolution
{
[ThreadLocal]
static DateTime _nextDispatchTime;
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
frame.Continue = false;
}));
Dispatcher.PushFrame(frame);
}
}
Comprobación DateTime.Now en DoEvents() no es en realidad requerido para que esta técnica funcione, pero mejorará el rendimiento si SomeProperty se configura con mucha frecuencia durante la deserialización.
Edit: Inmediatamente después de que escribí esto, me di cuenta de que hay una manera más fácil de implementar el método DoEvents. En lugar de utilizar DispatcherFrame, basta con utilizar Dispatcher.Invoke con una acción vacía:
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => {}));
}
He tenido un problema similar con mi panel que se movía sus artículos. La IU estaba congelada porque estaba usando un DispatcherTimer en la prioridad Cargado. El problema desapareció tan pronto como lo cambié a DispatcherPriority.Input.
- 1. Evite que Jsoup descarte espacios en blanco adicionales
- 2. ¿Por qué STDIN causa que se congele mi programa Perl?
- 3. Evite que el hilo principal se congele cuando UIWebView intente bloquear de forma bloqueada el hilo web
- 4. map.fitBounds (bounds) causando que el navegador se congele
- 5. Actualizar la IU desde múltiples hilos de trabajo (.NET)
- 6. Evite que se envíe spam a MediaWiki
- 7. Android - Elementos de IU que se apagan
- 8. Evite que Javascript se ejecute dos veces
- 9. Evite que XmlTextReader expanda entidades
- 10. ¿Cómo hacer que DataGridCheckBoxColumn sea editable sin requerir clics adicionales?
- 11. Mostrar imágenes devueltas como ActionResult (matriz de bytes) hace que IE6 se congele
- 12. Actualizar la IU mientras se trabaja en el fondo
- 13. CScript/WScript Evite que se produzca un error al bloquear
- 14. PyQt: ¿cómo detectar y cerrar la IU si ya se está ejecutando?
- 15. Evite voltear la cámara frontal
- 16. hilos que activan C#
- 17. Evite que Silverlight 3 cachee mientras depura
- 18. Evite que photoswipe oculte la barra de herramientas
- 19. ¿Sinatra tiene múltiples hilos?
- 20. Prueba de IU codificada VS 2010 - Inicie la aplicación a la que se hace referencia
- 21. sin detener todos los hilos en gdb
- 22. Guice: Evite la inyección diferida
- 23. Evite que Ruby on Rails 3 analice la publicación JSON
- 24. IU emergente WPF que muestra negro
- 25. Evite que JSON pretty_generate escape Unicode
- 26. Instrumentación de una IU
- 27. IU de autocompletado de jQuery: me gustaría iniciar la búsqueda en foco sin que el usuario tenga que escribir nada
- 28. Creando un archivo seguro sin hilos shared_ptr
- 29. ¿La TDD se aplica bien al desarrollar una IU?
- 30. Se agregaron espacios adicionales en la cola en la columna
En Windows Forms puede usar Application.DoEvents(). No sé si funciona en WPF. – Qwertie