Principales respuestas
Bloqueo UI

Pregunta
-
Hola!
Tengo un problemilla de bloqueo de UI, a ver que os parece. Trabajo en una aplicación que ataca a una url para obtener un json de datos que se parsea y se pinta en la UI.
Realizo las llamadas con un "BackgroundWorker" y pinto en la UI con "this.Dispatcher.BeginInvoke((Action)delegate(){ });". Durante la llamada y el procesado de datos todo va genial, el BackgroundWorker no me provoca bloqueos, es a la hora de pintar en la UI cuando noto el bloqueo.
¿Es posible solucionarlo?
Gracias!
Respuestas
-
Hola:
Creo que tienes un par de problemas en el código:
1. Estás ejecutando dos hilos, el primero lo lanzas con
worker = new BackgroundWorker(); worker.DoWork += new DoWorkEventHandler(LoadData);
el segundo cuando llamas a :
proyect.Backend.API.GetData(ID, (Data,Args)
ya que todas las llamadas a servicios se ejecutan asincronas. Lo que te recomiendo es que quites el BackgroundWorker.
Lo segundo que veo y que posiblemente es la que hace que se provoque esa sensación de refresco es el siguiente bloque de código.
foreach (var item in Data){ if(item.Title == ""){ item.Title = item.Content.Substring(0,30)+"..."; } var ObjectModel = new ObjectModel(){ ObjectID = item.ID.ToString(), ObjectContent = item.Content, ObjectTitle = '"'+item.Title+'"', ObjectDate = item.Date }; this.Dispatcher.BeginInvoke((Action)delegate(){ DataBox.Items.Add(ObjectModel); ProgressBar.Visibility = Visibility.Collapsed; dataLoaded = true; });
Porque no lo sustuyes por :
List<ObjectModel> Lista = new List<ObjectModel> foreach (var item in Data){ if(item.Title == ""){ item.Title = item.Content.Substring(0,30)+"..."; } var ObjectModel = new ObjectModel(){ ObjectID = item.ID.ToString(), ObjectContent = item.Content, ObjectTitle = '"'+item.Title+'"', ObjectDate = item.Date }; Lista.Add(ObjectModel); } this.Dispatcher.BeginInvoke((Action)delegate(){ DataBox.DataSource = ObjectModel; ProgressBar.Visibility = Visibility.Collapsed; dataLoaded = true; );
Lo que te quiero transmitir es que primero crees la colección de datos y después se la asignes a la propiedad DataSource del DataBox.
Con la linea DataBox.Items.Add(ObjectModel); estás provocando que la pantalla se refresque por cada elemento del DataBox, esto
suele ser bastante lento.
Espero que te sirva.
phurtado- Marcado como respuesta pjosh miércoles, 29 de junio de 2011 7:57
Todas las respuestas
-
Buenas!
Puedes poner por aquí el código que usas para pintar en la UI?? o alguno de ejemplo que sufra del mismo problema :) así nos hacemos una idea de que haces exactamente.
Un saludo!
MCTS .NET Framework 3.5 Windows Forms Application Development
MCTS .NET Framework 3.5 Windows Presentation Foundation
Visita mi Blog en Geeks.ms
Sigueme en Twitter -
Muchas gracias por tu respuesta Josue!
Ahí va el código:
//Esto se instancia en el constructor
worker = new BackgroundWorker(); worker.DoWork += new DoWorkEventHandler(LoadData);
//Método de la clase
void LoadData(object sender, DoWorkEventArgs e){ if(!dataLoaded){ this.Dispatcher.BeginInvoke((Action)delegate(){ ProgressBar.Visibility = Visibility.Visible; }); proyect.Backend.API.GetData(ID, (Data,Args) =>{ foreach (var item in Data){ if(item.Title == ""){ item.Title = item.Content.Substring(0,30)+"..."; } var ObjectModel = new ObjectModel(){ ObjectID = item.ID.ToString(), ObjectContent = item.Content, ObjectTitle = '"'+item.Title+'"', ObjectDate = item.Date }; this.Dispatcher.BeginInvoke((Action)delegate(){ DataBox.Items.Add(ObjectModel); ProgressBar.Visibility = Visibility.Collapsed; dataLoaded = true; }); } }); } }
Así cosas raras está la linea de "proyect.Backend.API.GetData". Esto básicamente es una clase que me he creado y llamado "API", que se encarga de gestionar todas las request de ataque al api donde obtengo los datos, para así tenerlo centralizado. También se encarga de procesar los datos y devolverme un objeto de un tipo definido por mi mediante un modelo.
Para que os hagáis una idea de los síntomas que tiene mi aplicación, cuando ejecuto el método pongo visible el ProgressBar y este transcurre con normalidad ajeno al trabajo en segundo plano del "worker". Y es un momento antes de que los datos sean pintados cuando noto que el ProgressBar sufre un pequeño parón.
También, si me pongo a moverme por el pivot mientras realiza el proceso, me congela un poco la navegación justo antes del pintado.
A ver si hay suerte... :P.
Muchas gracias!
-
Hola:
Creo que tienes un par de problemas en el código:
1. Estás ejecutando dos hilos, el primero lo lanzas con
worker = new BackgroundWorker(); worker.DoWork += new DoWorkEventHandler(LoadData);
el segundo cuando llamas a :
proyect.Backend.API.GetData(ID, (Data,Args)
ya que todas las llamadas a servicios se ejecutan asincronas. Lo que te recomiendo es que quites el BackgroundWorker.
Lo segundo que veo y que posiblemente es la que hace que se provoque esa sensación de refresco es el siguiente bloque de código.
foreach (var item in Data){ if(item.Title == ""){ item.Title = item.Content.Substring(0,30)+"..."; } var ObjectModel = new ObjectModel(){ ObjectID = item.ID.ToString(), ObjectContent = item.Content, ObjectTitle = '"'+item.Title+'"', ObjectDate = item.Date }; this.Dispatcher.BeginInvoke((Action)delegate(){ DataBox.Items.Add(ObjectModel); ProgressBar.Visibility = Visibility.Collapsed; dataLoaded = true; });
Porque no lo sustuyes por :
List<ObjectModel> Lista = new List<ObjectModel> foreach (var item in Data){ if(item.Title == ""){ item.Title = item.Content.Substring(0,30)+"..."; } var ObjectModel = new ObjectModel(){ ObjectID = item.ID.ToString(), ObjectContent = item.Content, ObjectTitle = '"'+item.Title+'"', ObjectDate = item.Date }; Lista.Add(ObjectModel); } this.Dispatcher.BeginInvoke((Action)delegate(){ DataBox.DataSource = ObjectModel; ProgressBar.Visibility = Visibility.Collapsed; dataLoaded = true; );
Lo que te quiero transmitir es que primero crees la colección de datos y después se la asignes a la propiedad DataSource del DataBox.
Con la linea DataBox.Items.Add(ObjectModel); estás provocando que la pantalla se refresque por cada elemento del DataBox, esto
suele ser bastante lento.
Espero que te sirva.
phurtado- Marcado como respuesta pjosh miércoles, 29 de junio de 2011 7:57
-
Buenas!
Totalmente de acuerdo con Pedro
Solo una cosa, por tu código veo que no estás usando enlace a datos ni MVVM para la aplicación, es muy recomendable que lo uses, puedes darle una lectura al 3º capítulo de mi libro sobre wp7 donde explico enlace a datos y MVVM para WP7:
Un saludo!
MCTS .NET Framework 3.5 Windows Forms Application Development
MCTS .NET Framework 3.5 Windows Presentation Foundation
Visita mi Blog en Geeks.ms
Sigueme en Twitter -
-