none
Bloqueo UI RRS feed

  • 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!

    lunes, 27 de junio de 2011 7:06

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
    martes, 28 de junio de 2011 9:54

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
    lunes, 27 de junio de 2011 17:08
    Moderador
  • 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!

    lunes, 27 de junio de 2011 19:38
  • 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
    martes, 28 de junio de 2011 9:54
  • 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:

    http://geeks.ms/blogs/jyeray/archive/2011/06/08/wp7-libro-por-cap-237-tulos-programar-en-silverlight-para-windows-phone-tercer-cap-237-tulo.aspx

    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
    martes, 28 de junio de 2011 11:56
    Moderador
  • Hola:

     

    Totalmente de acuerdo con Josue :)  no utilizar MVVM desde mi punto de vista es un error.

     

    Saludos,

    Pedro.


    phurtado
    martes, 28 de junio de 2011 12:02
  • Muchas gracias Pedro y Josue!!

    Me plantearé muy seriamente reestructurar la app para utilizar MVVM.

     

    Un saludo!

    miércoles, 29 de junio de 2011 7:58