THREAD PROBLEMA
Fala galera,
Seguinte estou com um pequeno grande problema....
Estou usando uma Thread para buscar dados do banco de dados sem travar o form....
Jogo o Resultado em um DataGridView, porem a ScrollBar do DataGridWiew Some, desaparece, se oculta ou qualquer outra coisa.....
Como que faço para que isso não ocorra!!!
Seguinte estou com um pequeno grande problema....
Estou usando uma Thread para buscar dados do banco de dados sem travar o form....
Jogo o Resultado em um DataGridView, porem a ScrollBar do DataGridWiew Some, desaparece, se oculta ou qualquer outra coisa.....
Como que faço para que isso não ocorra!!!
Isso ocorreu comigo, eu desabilitava ao iniciar a operação, e habilitava depois, sabe o que eu fiz ?
Parei de desabilitar, isso porque não descobri a causa.
Parei de desabilitar, isso porque não descobri a causa.
O que eu acho que você vai ter que fazer é criar outra thread para dar um enable no scrollbar já tentou ? ? ?
Meio difÃcil descobrir no chute o que pode estar acontecendo sem nenhum código para ver.
Uma dúvida, você faz a busca em uma thread e nela mesmo você modifica o DataGrid? Se sim esse pode ser o problema já que o acesso a métodos ou propriedades de controles fora da thread em que foram criados não garante o funcionamento correto dos controles.
Uma dúvida, você faz a busca em uma thread e nela mesmo você modifica o DataGrid? Se sim esse pode ser o problema já que o acesso a métodos ou propriedades de controles fora da thread em que foram criados não garante o funcionamento correto dos controles.
Deu muito Futuro Não os meus teste... Vou postar um exemplo de como que to fazendo:
Função que inicia a thread:
[txt-color=#0000f0]Privat Sub[/txt-color] Inicia_Thread()
[txt-color=#0000f0]Control[/txt-color].CheckForIllegalCrossThreadCalls = [txt-color=#0000f0]False[/txt-color]
Var_THR_Busca = [txt-color=#0000f0]New Thread[/txt-color]([txt-color=#0000f0]AddressOf[/txt-color] Busca_dados)
Var_THR_Busca.Start()
[txt-color=#0000f0]End Sub[/txt-color]
[txt-color=#0000f0]Privat Sub[/txt-color] Busca_dados()
[ô]Preenche os Dados
DataGridView_Registro.Rows.Add([txt-color=#e80000][Ô]False[Ô][/txt-color], _
[txt-color=#e80000][Ô]Dado 1[Ô][/txt-color], _
[txt-color=#e80000][Ô]Dado 2[Ô][/txt-color])
[txt-color=#0000f0]End Sub[/txt-color]
So que a ScrollBar do DataGrid não aparece....
Se eu adicionar sem usar a Thread a ScrollBar aparece normalmente!!!
Função que inicia a thread:
[txt-color=#0000f0]Privat Sub[/txt-color] Inicia_Thread()
[txt-color=#0000f0]Control[/txt-color].CheckForIllegalCrossThreadCalls = [txt-color=#0000f0]False[/txt-color]
Var_THR_Busca = [txt-color=#0000f0]New Thread[/txt-color]([txt-color=#0000f0]AddressOf[/txt-color] Busca_dados)
Var_THR_Busca.Start()
[txt-color=#0000f0]End Sub[/txt-color]
[txt-color=#0000f0]Privat Sub[/txt-color] Busca_dados()
[ô]Preenche os Dados
DataGridView_Registro.Rows.Add([txt-color=#e80000][Ô]False[Ô][/txt-color], _
[txt-color=#e80000][Ô]Dado 1[Ô][/txt-color], _
[txt-color=#e80000][Ô]Dado 2[Ô][/txt-color])
[txt-color=#0000f0]End Sub[/txt-color]
So que a ScrollBar do DataGrid não aparece....
Se eu adicionar sem usar a Thread a ScrollBar aparece normalmente!!!
Você não deve modificar nenhum controle dentro de outra thread pois pode acontecer coisas inesperadas. Esse é um dos maiores erros que as pessoas cometem ao usar Threads
Nunca mude o CheckForIllegalCrossThreadCalls, ele serve apenas para ajudar a debugar o programa, se setando ele como false faz algum erro não acontecer isso significa que você tem um erro no programa, na verdade essa propriedade é por padrão True apenas quando debugando o programa, pois ajuda a encontrar problemas, rodando o programa fora do Visual Studio ela já é false por padrão.
O correto ao se usar threads é fazer todo o trabalho que não precisa fazer nada com a interface, como por exemplo carregar um DataSet, e depois de carregado o DataSet você pode usar ele como DataSource do Grid, porém você deve fazer isso não nessa Thread e sim na Thread principal, que é a que criou o Form, para isso você usa o Invoke do objeto Control, segue um pequeno exemplo
Se eu tirar o Invoke ali e usar direto [ô]DataGridView1.DataSource = dados.Tables(0)[ô] acontece o que você fala de dar problema na barra de rolagem, com essa linha não acontece nenhum problema
Repare também que em vez de criar manualmente a Thread eu usei o ThreadPool.QueueUserWorkerItem para criar a Thread para mim, não tem muita diferença entre os dois quando se trata de apenas uma Tread, mas se tiver várias Threads usando o ThreadPool ele cria uma fila delas e executa uma certa quantidade de Threads de cada vez, mas no geral eu acho apenas mais prático usar o ThreadPool, e na verdade existem outras formas de se usar threads no .Net
Nunca mude o CheckForIllegalCrossThreadCalls, ele serve apenas para ajudar a debugar o programa, se setando ele como false faz algum erro não acontecer isso significa que você tem um erro no programa, na verdade essa propriedade é por padrão True apenas quando debugando o programa, pois ajuda a encontrar problemas, rodando o programa fora do Visual Studio ela já é false por padrão.
O correto ao se usar threads é fazer todo o trabalho que não precisa fazer nada com a interface, como por exemplo carregar um DataSet, e depois de carregado o DataSet você pode usar ele como DataSource do Grid, porém você deve fazer isso não nessa Thread e sim na Thread principal, que é a que criou o Form, para isso você usa o Invoke do objeto Control, segue um pequeno exemplo
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ThreadPool.QueueUserWorkItem(AddressOf CarregarDados)
End Sub
Private Sub CarregarDados(ByVal state As Object)
Dim cnn As New SqlConnection([Ô]Server=.\SQLEXPRESS;Database=MeuBancoDeDados;Trusted_Connection=True[Ô])
cnn.Open()
Dim cmd As New SqlCommand([Ô]SELECT * FROM MinhaTabela[Ô], cnn)
Dim adapter As New SqlDataAdapter(cmd)
Dim dados As New DataSet
adapter.Fill(dados)
[ô]Aqui se usa o Invoke que faz com que o código seja executado na thread principal
Invoke(Sub(d) DataGridView1.DataSource = d, dados.Tables(0))
cnn.Close()
cnn.Dispose()
adapter.Dispose()
cmd.Dispose()
End Sub
Se eu tirar o Invoke ali e usar direto [ô]DataGridView1.DataSource = dados.Tables(0)[ô] acontece o que você fala de dar problema na barra de rolagem, com essa linha não acontece nenhum problema
Repare também que em vez de criar manualmente a Thread eu usei o ThreadPool.QueueUserWorkerItem para criar a Thread para mim, não tem muita diferença entre os dois quando se trata de apenas uma Tread, mas se tiver várias Threads usando o ThreadPool ele cria uma fila delas e executa uma certa quantidade de Threads de cada vez, mas no geral eu acho apenas mais prático usar o ThreadPool, e na verdade existem outras formas de se usar threads no .Net
Perfeito o problema das ScrollBars foi resolvido, mas apareceu outro...
Usando seu exemplo ele cria colunas novas, como que eu faço para ele preencher as colunas já existentes...
Pois tem algumas colunas que são ocultas, e o Head delas ficam igual a do banco de dados e aparecer isso pro cliente não é legal!!!
que eu faço agora???
Usando seu exemplo ele cria colunas novas, como que eu faço para ele preencher as colunas já existentes...
Pois tem algumas colunas que são ocultas, e o Head delas ficam igual a do banco de dados e aparecer isso pro cliente não é legal!!!
que eu faço agora???
Se você já criou as colunas manualmente e definiu o nome do campo do banco de dados na propriedade DataPropertyName então coloque em algum lugar, pode ser no Load do Form ou antes de iniciar a thread a seguinte linha
DataGridView1.AutoGenerateColumns = False
Por algum motivo obscuro essa propriedade não aparece na janela de propriedades e tem que ser modificada por código
DataGridView1.AutoGenerateColumns = False
Por algum motivo obscuro essa propriedade não aparece na janela de propriedades e tem que ser modificada por código
O que não dá pra entender é:
1 - Porque achar que criar uma thread vai resolver o problema de preenchimento de grid.
2 - Por que preencher um grid manualmente, linha a linha, quando se pode simplesmente usar um DataReader e um List<T> passando o mesmo como DataSource
Ter Threads para executar tarefas, não torna nada mais rápido. Se você usar OOP e uma thread para preencher um List<T>, isso sim faria diferença de performance...
1 - Porque achar que criar uma thread vai resolver o problema de preenchimento de grid.
2 - Por que preencher um grid manualmente, linha a linha, quando se pode simplesmente usar um DataReader e um List<T> passando o mesmo como DataSource
Ter Threads para executar tarefas, não torna nada mais rápido. Se você usar OOP e uma thread para preencher um List<T>, isso sim faria diferença de performance...
KERPLUNK não é questão de performance que uso a thread....
A questão é o SERVIDOR fica longe (outro pais) do Computador CLIENTE...
Uso a thread para o FORM não ficar travado e mostrar pro usuário que o processo de busca esta acontecendo... Entendeu!!!!
Teria outra forma de fazer essa busca sem travar o FORM???
Algumas coisas eu ainda estou aprendendo e thread e uma coisa nova pra mim....
No caso o que seria OOP e List<T> ???
------
OCELOT To dando uma olhada na sua dica pra ver o que eu faço!!!!
A questão é o SERVIDOR fica longe (outro pais) do Computador CLIENTE...
Uso a thread para o FORM não ficar travado e mostrar pro usuário que o processo de busca esta acontecendo... Entendeu!!!!
Teria outra forma de fazer essa busca sem travar o FORM???
Algumas coisas eu ainda estou aprendendo e thread e uma coisa nova pra mim....
No caso o que seria OOP e List<T> ???
------
OCELOT To dando uma olhada na sua dica pra ver o que eu faço!!!!
OOP = Object Oriented Programming
List<T> = Uma lista de objetos(classes) que descrevem uma fonte de dados, geralmente uma tabela.
Para entender melhor, seria algo assim(pseudo-código)
No pseudo-código acima, você abre um DataReader que vai conter o retorno de uma query. Para cada Ãtem, você aciona uma thread que vai preencher o Ãtem com os dados do DataReader, para cada linha retornada. Isso vai fazer a leitura ficar muito mais rápida, visto que os Ãtems serão lidos [Ô]todos ao mesmo tempo[Ô] praticamente. Além disso, com os eventos que são acionados durante a leitura e ao final dela, basta fazer um delegate no seu form para monitorá-las, assim, você pode passar para o usuário que os dados estão sendo lidos e também quando essa leitura terminou.
List<T> = Uma lista de objetos(classes) que descrevem uma fonte de dados, geralmente uma tabela.
Para entender melhor, seria algo assim(pseudo-código)
Retorno = List<MinhaClasse>
AbreConexao => con
ComandoSQL(Select * from tabelaX, con) => cmd
DataReader dr = cmd.ExecuteReader
While dr.HasRows
{
MinhaClasse item = new MinhaClasse()
Thread => PreencherItem(item, DadosDoDataReader)
Adicionar(item => Retorno)
AcionarEvento(LendoDados)
}
AcionarEvento(DadosLidos)
Retornar Retorno
No pseudo-código acima, você abre um DataReader que vai conter o retorno de uma query. Para cada Ãtem, você aciona uma thread que vai preencher o Ãtem com os dados do DataReader, para cada linha retornada. Isso vai fazer a leitura ficar muito mais rápida, visto que os Ãtems serão lidos [Ô]todos ao mesmo tempo[Ô] praticamente. Além disso, com os eventos que são acionados durante a leitura e ao final dela, basta fazer um delegate no seu form para monitorá-las, assim, você pode passar para o usuário que os dados estão sendo lidos e também quando essa leitura terminou.
Faça seu login para responder