none
ProgessBar em tempo de execução C# RRS feed

  • Pergunta

  • Olá Pessoal.

    A necessidade é fazer um progressBar que evolua em tempo de pesquisa e preenchimento do datagridview.

    O detalhe é que as consultas são diferentes, ou seja, agumas mais tempo de pesquisa e outra menos.

    consigo fazer ele funcionar, porem dempendendo da consulta ele preenche antes ou preenche depois da atualização do datagridview.

    se alguem puder me ajudar, agradeço.

    segue abaixo o codigo que estou usando.

    con.Open();
                            sql = "SELECT TECNICO, ESTACAO, ATIVIDADE, ESTADO, TERMINAL, REINCIDENCIA, REPAROGARANTIA, INICIOEXECUCAO, INICIOAGENDAMENTO FROM Base_SC WHERE GRA ='" + cbxGra.Text + "'";
                            sql = sql + " AND TECNICO LIKE '" + OSC + "%'";
                            sql = sql + " ORDER BY TECNICO DESC, INICIOEXECUCAO ASC";
                            System.Data.OleDb.OleDbCommand cmd = new System.Data.OleDb.OleDbCommand(sql, con);
                            OleDbDataAdapter da = new OleDbDataAdapter(cmd);
                            DataTable dt = new DataTable();
                            da.Fill(dt);
                            dgvAbertas.DataSource = dt;
                            progressBar1.Maximum = dt.Rows.Count;
                            progressBar1.Minimum = 0;
                            progressBar1.Step = 1;
                            for (int i = 0; i < dt.Rows.Count; i++)
                            {
                                progressBar1.Value = i;                           
    
                            }
                            formataGridView();

    domingo, 8 de junho de 2014 19:49

Respostas

  • Certo.Você pode utilizá-los normalmente,porém,se tiver que acessar alguma propriedade de algum controle,é necessário criar uma "requisição" para a thread usando o método Invoke,como usei anteriormente.

    Um exemplo é a linha:

    lblContaTudo.Text = "Total Selecionado " + dt.Rows.Count + " Atividades";

    Você está atribuindo um valor para a propriedade Text do objeto,porém,este está numa thread secundária,então é necessário criar a requisição

    lblContaTudo.Invoke(new MethodInvoker(() => { lblContaTudo.Text = "Total Selecionado " + dt.Rows.Count + " Atividades"; }));

    Tenha em mente que deve ser feito com qualquer objeto que esteja na thread.
    É claro,você pode criar um método para facilitar e deixar o código melhor e mais limpo

    private void MudarTextolblContaTudo(string texto)
    {
    	lblContaTudo.Invoke(new MethodInvoker(() => { lblContaTudo.Text = texto; }));
    }

    MudarTextolblContaTudo("Total Selecionado " + dt.Rows.Count + " Atividades");

    Espero que tenha ajudado.

    Não hesite em perguntar,estamos aqui para ajudar :)

    segunda-feira, 9 de junho de 2014 23:31
  • Opa,falha minha novamente,pequeno erro de sintaxe haha,me desculpe :)

    Aqui está:

    private void LerDados()
    {
    	con.Open();
    	sql = "SELECT TECNICO, ESTACAO, ATIVIDADE, ESTADO, TERMINAL, REINCIDENCIA, REPAROGARANTIA, INICIOEXECUCAO, INICIOAGENDAMENTO FROM Base_SC WHERE GRA ='" + cbxGra.Text + "'";
    	sql = sql + " AND TECNICO LIKE '" + OSC + "%'";
    	sql = sql + " ORDER BY TECNICO DESC, INICIOEXECUCAO ASC";
    	System.Data.OleDb.OleDbCommand cmd = new System.Data.OleDb.OleDbCommand(sql, con);
    	OleDbDataAdapter da = new OleDbDataAdapter(cmd);
    	DataTable dt = new DataTable();
    	da.Fill(dt);
    	
    	//Criar as colunas
    	foreach (DataColumn coluna in dt.Columns)
    	{
    		dgvAbertas.Invoke(new MethodInvoker(() => { dgvAbertas.Columns.Add(coluna.Caption, coluna.Caption); }));
    	}
    	
    	//Definir o valor máximo a ser carregado
    	progressBar1.Invoke(new MethodInvoker(() => { progressBar1.Maximum = dt.Rows.Count; }));
    
    	//Carregar os dados
    	for(int linha = 0; linha < dt.Rows.Count; linha++)
    	{
    		dgvAbertas.Invoke(new MethodInvoker(() => {dgvAbertas.Rows.Add();}));
    		for(int coluna = 0; coluna < dt.Columns.Count; coluna++)
    		{
    			dgvAbertas.Invoke(new MethodInvoker(() => { dgvAbertas.Rows[linha].Cells[coluna].Value = dt.Rows[linha][coluna]; }));
    		}
    		progressBar1.Invoke(new MethodInvoker(() => { progressBar1.Value += 1; }));
    	}
    }

    Agora vai! :)


    segunda-feira, 9 de junho de 2014 20:57
  • Guilherme

    Funcinou perfeitamente, obrigado.

    Alterei todos e está OK.

    no caso de um metodo como o abaixo.

     private void formataGridView()
            {                        
                var formtaDgvabert = dgvAbertas;
                formtaDgvabert.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders;
                formtaDgvabert.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;
                //altera a cor das linhas alternadas no grid
                formtaDgvabert.RowsDefaultCellStyle.BackColor = Color.White;

    percebe que ali tem var e tenho alguns com int.

    neste caso é um pouco mais complexo que somente mudar um label ou textbox.

    tens alguma sugestao?

    se tiveres algum material, nao exite em me passar que vou estudando.

    obrigado

    segunda-feira, 9 de junho de 2014 23:58

Todas as Respostas

  • Oi, boa tarde, vamos lá...

    Primeiro, você vai adicionar um componente de thread chamado BackgroundWorker...nas propriedades dele você modifica WorkerReportsProgress para True, isso fará com que ele nos informe a sua progressão.

    Vou deixar um código de exemplo, espero que te ajude, abraço!!!

    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
              
             
            }
    
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                //Aqui você chama o método que fará o SELECT no banco
                int num = 0;
                for (int i = 0; i < 100; i++)
                {
                    num += i;
                    backgroundWorker1.ReportProgress(i);
                }
            }
    
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                MessageBox.Show("Executado com sucesso!");
            }
    
            private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                progressBar1.Value = e.ProgressPercentage;
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                backgroundWorker1.RunWorkerAsync();
            }    
          
    
        }
    
       
    }

    domingo, 8 de junho de 2014 20:12
  • ola diego

    não deu certo.

    coloquei um ponto de interrupção na funçao do button1 e simplesmente nao avaça.

    o que pode se?

    domingo, 8 de junho de 2014 20:39
  • Diego

    pela sua sugestao

    roda parcialmente.

    me deparei com o seguinte erro:

    Operação entre threads inválida: controle 'dgvAbertas' acessado de um thread que não é aquele no qual foi criado.

    e isto acontece tambem com as variaveis que criei dentro do método que faz a chamado para o select.

    tens alguma ideia do que pode ser?

    domingo, 8 de junho de 2014 20:52
  • Marcos, esse erro ocorre porque você manipulou um objeto do qual foi criado pela thread principal do Windows Form a STAThread, o componente background abre uma thread a parte e não consegue manipular de outras threads, se for preciso manipular algo no seu grid coloque tudo no evento 'RunWorker_Completed' aí não ocasiona esse erro chatinho...ao decorrer, vai nos falando...
    segunda-feira, 9 de junho de 2014 01:38
  • Olá,você pode criar um método

    private void LerDados()
    {
    	con.Open();
    	sql = "SELECT TECNICO, ESTACAO, ATIVIDADE, ESTADO, TERMINAL, REINCIDENCIA, REPAROGARANTIA, INICIOEXECUCAO, INICIOAGENDAMENTO FROM Base_SC WHERE GRA ='" + cbxGra.Text + "'";
    	sql = sql + " AND TECNICO LIKE '" + OSC + "%'";
    	sql = sql + " ORDER BY TECNICO DESC, INICIOEXECUCAO ASC";
    	System.Data.OleDb.OleDbCommand cmd = new System.Data.OleDb.OleDbCommand(sql, con);
    	OleDbDataAdapter da = new OleDbDataAdapter(cmd);
    	DataTable dt = new DataTable();
    	da.Fill(dt);
    
    	//Criar as colunas
    	foreach(DataColumn coluna in dt.Columns)
    	{
    		dvgAbertas.Invoke(new MethodInvoker(() => { dvgAbertas.Columns.Add(coluna, coluna); }));
    	}
    
    	//Adicionar as linhas + progresso
    	progressBar1.Invoke(new MethodInvoker(() => { progressBar1.Maximum = dt.Rows.Count; }));
    	for(int linha = 0; linha < dt.Rows.Count; linha++)
    	{
    		for(int coluna = 0; coluna < dt.Columns; coluna++)
    		{
    			dvgAbertas.Invoke(new MethodInvoker(() => { dvgAbertas.Rows[linha].Cells[coluna].Value = dt.Rows[linha].Cells[coluna].Value; }));
    		}
    		progressBar1.Invoke(new MethodInvoker(() => { progressBar1.Value += 1; }));
    	}
    }

    e chamá-lo em uma thread

    Thread thLerDados = new Thread(LerDados);
    thLerDados.Start();

    segunda-feira, 9 de junho de 2014 08:11
  • Guilherme

    nestre ponto tem algo de errado:

    { dvgAbertas.Columns.Add(coluna, coluna); }));
    	}

    o que voce acha?

    segunda-feira, 9 de junho de 2014 13:32
  • Tente converter para string:

    dvgAbertas.Invoke(new MethodInvoker(() => { dvgAbertas.Columns.Add(coluna.ToString(), coluna.ToString()); }));

    segunda-feira, 9 de junho de 2014 18:51
  • ola guilherme

    este caso resolvido, porem o problema partiu para linha seguinte.

    for (int coluna = 0; coluna < dt.Columns; coluna++)

    nem convertendo foi.

    segunda-feira, 9 de junho de 2014 19:32
  • Ah sim,retorna uma coleção de Colunas,então basta usar a propriedade Count.

    for(int coluna = 0; coluna < dt.Columns.Count; coluna++)

    Falha minha haha!Fiz de cabeça,me desculpe (:

    segunda-feira, 9 de junho de 2014 19:48
  • grande ajuda Guilherme

    porem agora "enroscos" no Cells abaixo.

    { dgvAbertas.Rows[linha].Cells[coluna].Value = dt.Rows[linha].Cells[coluna].Value; }));

    me desculpe estar lhe perturbando, mas sou iniciante.

    obrigado

    segunda-feira, 9 de junho de 2014 20:24
  • Opa,falha minha novamente,pequeno erro de sintaxe haha,me desculpe :)

    Aqui está:

    private void LerDados()
    {
    	con.Open();
    	sql = "SELECT TECNICO, ESTACAO, ATIVIDADE, ESTADO, TERMINAL, REINCIDENCIA, REPAROGARANTIA, INICIOEXECUCAO, INICIOAGENDAMENTO FROM Base_SC WHERE GRA ='" + cbxGra.Text + "'";
    	sql = sql + " AND TECNICO LIKE '" + OSC + "%'";
    	sql = sql + " ORDER BY TECNICO DESC, INICIOEXECUCAO ASC";
    	System.Data.OleDb.OleDbCommand cmd = new System.Data.OleDb.OleDbCommand(sql, con);
    	OleDbDataAdapter da = new OleDbDataAdapter(cmd);
    	DataTable dt = new DataTable();
    	da.Fill(dt);
    	
    	//Criar as colunas
    	foreach (DataColumn coluna in dt.Columns)
    	{
    		dgvAbertas.Invoke(new MethodInvoker(() => { dgvAbertas.Columns.Add(coluna.Caption, coluna.Caption); }));
    	}
    	
    	//Definir o valor máximo a ser carregado
    	progressBar1.Invoke(new MethodInvoker(() => { progressBar1.Maximum = dt.Rows.Count; }));
    
    	//Carregar os dados
    	for(int linha = 0; linha < dt.Rows.Count; linha++)
    	{
    		dgvAbertas.Invoke(new MethodInvoker(() => {dgvAbertas.Rows.Add();}));
    		for(int coluna = 0; coluna < dt.Columns.Count; coluna++)
    		{
    			dgvAbertas.Invoke(new MethodInvoker(() => { dgvAbertas.Rows[linha].Cells[coluna].Value = dt.Rows[linha][coluna]; }));
    		}
    		progressBar1.Invoke(new MethodInvoker(() => { progressBar1.Value += 1; }));
    	}
    }

    Agora vai! :)


    segunda-feira, 9 de junho de 2014 20:57
  • guilherme

    funcionou, porem surgiu outra questao.

    chamei na thead conforme voce sugeriu e ele preenche o progressbar perfeitamente.

    ficou mais lento o carregamento de dados e o X da questao agora sao os demais metodos que eu ja chamava dentro do metodo 'pesquisar" ou renomeado em sua sugestao como  "LerDados".

    na sequencia do meu metodo, tenho o metodo que formata o dgv, que faz o calculo de algumas colunas etc etc...

    entendeu o problema?

    obrigado

    segunda-feira, 9 de junho de 2014 22:09
  • Entendi,mas....o que está havendo?Não está conseguindo realizar?
    segunda-feira, 9 de junho de 2014 23:08
  • pelo que entendi, necessito chamar um thead dentro do outro.

    LerDados chamo no thead e dentro deste necessito chamar o meu outro metodo (alguns metodos na verdade).

    http://www.macoratti.net/10/09/c_thd1.htm

    olhei aqui e crei ser isto mesmo, porem preciso entender e fazer funcionar.

    veja como ficou o codigo agora (identifico os metodos externos que necessito chamar)

     con.Open();
                            sql = "SELECT TECNICO, ESTACAO, ATIVIDADE, ESTADO, TERMINAL, REINCIDENCIA, REPAROGARANTIA, INICIOEXECUCAO, INICIOAGENDAMENTO FROM Base_SC WHERE GRA ='" + gra + "'";
                            //ORDENAR DUAS COLUNAS COM SQL UMA CRESCENDENTE E OUTRA DECRESCENTE
                            sql = sql + " ORDER BY TECNICO DESC, INICIOEXECUCAO ASC";
                            System.Data.OleDb.OleDbCommand cmd = new System.Data.OleDb.OleDbCommand(sql, con);
                            OleDbDataAdapter da = new OleDbDataAdapter(cmd);
                            DataTable dt = new DataTable();
                            da.Fill(dt);
                            foreach (DataColumn coluna in dt.Columns)
                            {
                                dgvAbertas.Invoke(new MethodInvoker(() => { dgvAbertas.Columns.Add(coluna.Caption, coluna.Caption); }));
                            }
                            //Definir o valor máximo a ser carregado
                            progressBar1.Invoke(new MethodInvoker(() => { progressBar1.Maximum = dt.Rows.Count; }));
                            //Carregar os dados
                            for (int linha = 0; linha < dt.Rows.Count; linha++)
                            {
                                dgvAbertas.Invoke(new MethodInvoker(() => { dgvAbertas.Rows.Add(); }));
                                for (int coluna = 0; coluna < dt.Columns.Count; coluna++)
                                {
                                    dgvAbertas.Invoke(new MethodInvoker(() => { dgvAbertas.Rows[linha].Cells[coluna].Value = dt.Rows[linha][coluna]; }));
                                }
                                progressBar1.Invoke(new MethodInvoker(() => { progressBar1.Value += 1; }));
                            }
                            //abaixo os metodos externos que necessito chamar
                            formataGridView();
                            lblContaTudo.Text = "Total Selecionado " + dt.Rows.Count + " Atividades";
                            CorCelula();
                            contarRepetidos();
    

    nao sei se me fiz entender.

    obrigado pela sua paciencia.

    segunda-feira, 9 de junho de 2014 23:14
  • Certo.Você pode utilizá-los normalmente,porém,se tiver que acessar alguma propriedade de algum controle,é necessário criar uma "requisição" para a thread usando o método Invoke,como usei anteriormente.

    Um exemplo é a linha:

    lblContaTudo.Text = "Total Selecionado " + dt.Rows.Count + " Atividades";

    Você está atribuindo um valor para a propriedade Text do objeto,porém,este está numa thread secundária,então é necessário criar a requisição

    lblContaTudo.Invoke(new MethodInvoker(() => { lblContaTudo.Text = "Total Selecionado " + dt.Rows.Count + " Atividades"; }));

    Tenha em mente que deve ser feito com qualquer objeto que esteja na thread.
    É claro,você pode criar um método para facilitar e deixar o código melhor e mais limpo

    private void MudarTextolblContaTudo(string texto)
    {
    	lblContaTudo.Invoke(new MethodInvoker(() => { lblContaTudo.Text = texto; }));
    }

    MudarTextolblContaTudo("Total Selecionado " + dt.Rows.Count + " Atividades");

    Espero que tenha ajudado.

    Não hesite em perguntar,estamos aqui para ajudar :)

    segunda-feira, 9 de junho de 2014 23:31
  • Guilherme

    Funcinou perfeitamente, obrigado.

    Alterei todos e está OK.

    no caso de um metodo como o abaixo.

     private void formataGridView()
            {                        
                var formtaDgvabert = dgvAbertas;
                formtaDgvabert.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders;
                formtaDgvabert.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;
                //altera a cor das linhas alternadas no grid
                formtaDgvabert.RowsDefaultCellStyle.BackColor = Color.White;

    percebe que ali tem var e tenho alguns com int.

    neste caso é um pouco mais complexo que somente mudar um label ou textbox.

    tens alguma sugestao?

    se tiveres algum material, nao exite em me passar que vou estudando.

    obrigado

    segunda-feira, 9 de junho de 2014 23:58
  • Basta usar o Invoke normalmente

    formtaDgvabert.Invoke(new MethodInvoker(() => { formtaDgvabert.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders; }));

    Lembre-se se usar métodos para não deixar o código poluído.

    terça-feira, 10 de junho de 2014 00:20
  • olha só Guilherme

    formtaDgvabert é a variavel no metodo formataGridView e neste caso nao é possivel usar o invoke no meu metodo e tambem nao consigo usar invoke para chamar o metodo formataGridView.

    ele nao faz parte do contexto atual.

    foi neste mesmo ponto que me "enrosquei" antes.

    terça-feira, 10 de junho de 2014 00:30
  • Olá,eu consegui utilizar sem problemas:

    Está recebendo alguma exceção?Algum erro?

    terça-feira, 10 de junho de 2014 00:42
  • Olá

    Afirma que foi criado em outro Thead.

    Mesmo erro anterior.

    terça-feira, 10 de junho de 2014 14:21
  • Você deve usar o método Invoke.
    Me mostre seu código atual e a linha que gera a exceção.
    terça-feira, 10 de junho de 2014 14:29
  • Olá Guilherme

    Andei meio ausente e não consegui responder.

    Deu tudo certo e está funcionando perfeitamente.

    Agradeço a sua atenção e sua paciencia.

    Abraço

    quinta-feira, 12 de junho de 2014 12:56