none
Carregar DataGridView de forma assíncrona! RRS feed

  • Pergunta

  • Boa tarde!

    Tenho um controle DataGridView em um form. onde está sendo carregado através de um dataset. Estou usando o componente backgroundworker para trabalhar de forma assíncrona mas mesmo assim trava no momento de carregar o DataGridView...

    Estou carregando da seguinte forma:

     

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {

               bgwPesquisa.ReportProgress(100);

               string csql = "SELECT CODIGOPES, NOMEPES, SRFPES, FONEPES FROM PESSOAS"

     

               ds = new dataset();

               da.SelectCommand = geral.RetornarDataCommand(csql);

              da.Fill(ds);

    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)

    {

            pgbAndamento.Value = e.ProgressPercentage;

    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

    }
              dataGridViewPessoa.DataSource = ds.tables[0];        
              pgbAndamento.Visible = false;

    }

           

     A linha que deixa o form. travado é: (dataGridViewPessoa.DataSource = ds.tables[0];)...
    Eu gostaria de saber como faço para carregar essa linha de forma assíncrona? porque mesmo usando o controle backgroundworker, o form. trava nessa linha..

    Estou programando em visual studio 2008 (C#) windows forms...

    Desde já, agradeço pela ajuda e atenção de todos...
    Muito Obrigado...

     

     

     

     

    • Editado Borges2 quarta-feira, 2 de setembro de 2009 14:53 Atualização
    segunda-feira, 24 de agosto de 2009 20:35

Respostas

  • Utilizando delegate é possível fazer chamadas assíncronas . Veja o código abaixo resolve o problema:

            public void DataGridView_Preencher()
            {
                dataGridViewPessoa.DataSource = ds.tables[0];            
            }
    
            delegate void Preencher();
    
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
            {
                Preencher deleg = new Preencher(DataGridView_Preencher);
                deleg.BeginInvoke(new AsyncCallback(FimDoDelegate),null);
            }
    
            // função chamada após execução do método assíncrono
            public void FimDoDelegate(IAsyncResult res)
            {            
                pgbAndamento.Visible = false;
            }

    OBS: sobrescreva o  método o seu método backgroundWorker1_RunWorkerCompleted pelo do código acima, mas mantenha os demais métodos criado por você.

    • Sugerido como Resposta Milton Castro terça-feira, 25 de agosto de 2009 09:41
    • Marcado como Resposta Borges2 quarta-feira, 22 de junho de 2011 11:43
    terça-feira, 25 de agosto de 2009 09:40
  • Borges,

    A thread criada pelo BackgroundWorker está tentando acessar um controle da main thread, o que acusa o erro. Você terá que utilizar a propriedade InvokeRequired para verificar a chamada.

    Verifique os links abaixo:

    Control.InvokeRequired Property
    http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx

    How to: Make Thread-Safe Calls to Windows Forms Controls
    http://msdn.microsoft.com/en-us/library/ms171728.aspx

    Dealing With GUI Threading Issues
    http://codinghut.com/2009/04/dealing-with-gui-threading-issues/

    Att.

    Ari C. Raimundo
    • Marcado como Resposta Borges2 quarta-feira, 22 de junho de 2011 11:43
    terça-feira, 25 de agosto de 2009 12:26
    Moderador
  • Borges,

    não sei se vai resolver, mas nesse caso eu faria a inserção linha-a-linha do DataGridView no método  DataGridView_Preencher. Seria algo desse tipo:

    public void DataGridView_Preencher()
    {          
        foreach (DataRow linha in ds.Tables[0].Select())
        {
            dataGridViewPessoa.Rows.Add(
                linha["CODIGOPES"].ToString(),
                linha["NOMEPES"].ToString(),
                linha["SRFPES"].ToString(),
                linha["FONEPES"].ToString());
        }
    }
    • Marcado como Resposta Borges2 quarta-feira, 22 de junho de 2011 11:44
    terça-feira, 25 de agosto de 2009 23:03

Todas as Respostas

  • Utilizando delegate é possível fazer chamadas assíncronas . Veja o código abaixo resolve o problema:

            public void DataGridView_Preencher()
            {
                dataGridViewPessoa.DataSource = ds.tables[0];            
            }
    
            delegate void Preencher();
    
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
            {
                Preencher deleg = new Preencher(DataGridView_Preencher);
                deleg.BeginInvoke(new AsyncCallback(FimDoDelegate),null);
            }
    
            // função chamada após execução do método assíncrono
            public void FimDoDelegate(IAsyncResult res)
            {            
                pgbAndamento.Visible = false;
            }

    OBS: sobrescreva o  método o seu método backgroundWorker1_RunWorkerCompleted pelo do código acima, mas mantenha os demais métodos criado por você.

    • Sugerido como Resposta Milton Castro terça-feira, 25 de agosto de 2009 09:41
    • Marcado como Resposta Borges2 quarta-feira, 22 de junho de 2011 11:43
    terça-feira, 25 de agosto de 2009 09:40
  • Blz Milton?

    Então, fiz as modificações no método RunWorkerCompleted como vc tinha falado, mas agora está aparecendo uma mensagem de erro no método DataGridView_Preencher()..

    Está com a seguinte mensagem de erro: Operação entre threads inválida: controle 'DataGridViewPessoa' acessado de um thread que não é aquele no qual foi criado. Tem alguma sugestão de como resolver esse problema?

    terça-feira, 25 de agosto de 2009 12:08
  • Borges,

    A thread criada pelo BackgroundWorker está tentando acessar um controle da main thread, o que acusa o erro. Você terá que utilizar a propriedade InvokeRequired para verificar a chamada.

    Verifique os links abaixo:

    Control.InvokeRequired Property
    http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx

    How to: Make Thread-Safe Calls to Windows Forms Controls
    http://msdn.microsoft.com/en-us/library/ms171728.aspx

    Dealing With GUI Threading Issues
    http://codinghut.com/2009/04/dealing-with-gui-threading-issues/

    Att.

    Ari C. Raimundo
    • Marcado como Resposta Borges2 quarta-feira, 22 de junho de 2011 11:43
    terça-feira, 25 de agosto de 2009 12:26
    Moderador
  • Milton,

    Efetuei as alterações no método RunWorkerCompleted como vc sugeriu, mas continua travando na linha (DataGridView.DataSource = ds.tables[0]).. Por que será que está travando mesmo no processo assíncrono?

    terça-feira, 25 de agosto de 2009 15:06
  • Borges,

    não sei se vai resolver, mas nesse caso eu faria a inserção linha-a-linha do DataGridView no método  DataGridView_Preencher. Seria algo desse tipo:

    public void DataGridView_Preencher()
    {          
        foreach (DataRow linha in ds.Tables[0].Select())
        {
            dataGridViewPessoa.Rows.Add(
                linha["CODIGOPES"].ToString(),
                linha["NOMEPES"].ToString(),
                linha["SRFPES"].ToString(),
                linha["FONEPES"].ToString());
        }
    }
    • Marcado como Resposta Borges2 quarta-feira, 22 de junho de 2011 11:44
    terça-feira, 25 de agosto de 2009 23:03
  • Milton,

    eu queria ver contigo se tem outra forma de popular um DataGridView de forma assíncrona, porque fiz uns testes aqui referente ao seu ultimo exemplo inserindo linha por linha no DataGridView e realmente não trava o form. mas demora muito para terminar de carregar todas as linhas. Queria ver contigo se para carregar um DataGridView de forma assíncrona, se teria outra forma ou somente inserindo linha por linha mesmo, como vc sugeriu no último exemplo?

    quarta-feira, 26 de agosto de 2009 15:05
  • Tenta isso daqui:
    public void DataGridView_Preencher()
    {
            BindingSource bindingSource1 = new BindingSource();
            dataGridViewPessoa.DataSource = ds.tables[0];
            dataGridViewPessoa.DataSource = bindingSource1; 
    }
    quinta-feira, 27 de agosto de 2009 16:32
  • Milton,

    testei aqui e dessa forma que vc sugeriu, o dataGridView fica nulo. Testei tambem da seguinte forma:

    BindingSource bindingsource1 = new BindingSource();

    bindingsource1.DataSource = ds.tables[0];

    dataGridViewPessoa.DataSource = bindingsource1;

    Dessa forma, o form. tambem trava no momento que está sendo carregado o DataGridView... Tem alguma idéia de como posso resolver esse problema ou somente carregando linha por linha mesmo? sempre lembrando de popular o DataGridView de forma assíncrona... 

    quinta-feira, 27 de agosto de 2009 17:27
  • Desculpe a minha falta de atenção, era pra testar da maneira que você sugeriu. Mas de qualquer forma não ia funcionar, né? Outra coisa que você pode tentar é:

    public void DataGridView_Preencher()
    {
            BindingSource bindingSource1 = new BindingSource();
            bindingSource1.DataSource = ds.tables[0];
    }
    
    public void FimDoDelegate(IAsyncResult res)
    {            
            dataGridViewPessoa.DataSource = bindingSource1;
            pgbAndamento.Visible = false;
    }
    quinta-feira, 27 de agosto de 2009 18:33
  • Milton,

    testei aqui e dessa forma tambem trava o form. no momento do carregamento do dataGridView. Agora surgiu mais dúvidas... Eu estou achando que não tem como popular um DataGridView através do seu DataSource de forma assíncrona, será que é isso mesmo ou deve ter um jeito sim? Será que carregamento assíncrono só é possível apenas carregando o dataGridView linha por linha?

    sexta-feira, 28 de agosto de 2009 14:20