PROBLEMA COM CABECALHO DATAGRIDVIEW

LUIS.HERRERA 16/01/2014 10:02:27
#433134
Bom dia.

Estou tendo um problema com Datagridview.

Inclui o código abaixo para evitar que o grid preenchesse os campos no form, quando se clicar no cabeçalho da coluna, pois pegava sempre a primeira linha de dados, mas o correto é preencher só se clicar na linha e não no cabeçalho.


private void grid_Click(object sender, EventArgs e)
{
if ((grid.CurrentRow == null) || (grid.CurrentRow.Selected == false))
return;


Ok está funcionando, porém quero que ao clicar no cabeçalho, as linhas sejam ordenadas(primeiro clique ascendente, segundo clique descendente).

Li que isso é automático, mas não está funcionando. Pesquisei mas não consegui resolver, pois todos os exemplos não são compatíveis com o meu caso, onde povoo o grid com um List na propriedade DataSource.

Alguém sabe como resolver isso?

LUIS.HERRERA 16/01/2014 17:09:38
#433180
Bem na base da tentativa e erro, pois isso automático não funciona do grid, não sei onde viram que funcionava, consegui, mas é meio trabalhoso, pois se tem de fazer em cada form, para cada grid e identificar no Switch a coluna que ser quer ordenar e como. Ficou assim:

Se cria no início do form uma variável static para se setar o tipo de ordenação ascendente ou descendente, de modo que o sistema marque o último tipo selecionado.

static string coluna3 = [Ô]Descendente[Ô];

Agora se usa o evento do datagrid abaixo:

private void grid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
switch (e.ColumnIndex -1) // aqui identifico a coluna clicada no grid, tem que subtrair 1 pois ele considera a coluna iniciando em 1 e não no zero.
{
case 3:
coluna3 = coluna3 == [Ô]Ascendente[Ô] ? [Ô]Descendente[Ô] : [Ô]Ascendente[Ô]; //aqui troco o tipo para inverter no próximo clique do cabeçalho.
OrderGrid([Ô]Nome[Ô], coluna3); //chamo o método ordenar, informando o nome da coluna e o tipo de ordenação pela variável coluna3
break;
}
}


nota: para cada coluna será preciso ter uma variável estática e incrementar o switch. Pode existir uma forma mais prática e que evite fazer uma instrução para cada coluna etc.. mas não tive tempo para otimizar isso agora.

O método de orcenação. pego os dados do grid num list, ordeno e devolvo ao grid

private void OrderGrid(string myNomeColuna, string myDirecao)
{
List<InstrutoresModelo> instrutor = grid.DataSource as List<InstrutoresModelo>;

switch (myNomeColuna)
{
case [Ô]Nome[Ô]:
if (myDirecao == [Ô]Ascendente[Ô])
instrutor = instrutor.OrderBy(c => c.Nome.Trim()).ToList(); //ordena ascendente
else
instrutor = instrutor.OrderByDescending(c => c.Nome.Trim()).ToList(); //ordena descendente
break;
}
grid.DataSource = instrutor; //devolvo a lista ordenada ao grid
}


Bem amigos é isso, está funcionando perfeitamente, agora se alguém souber de uma forma mais prática, que facilite otimizar a identificação de qual coluna foi clicada, e reduzir o código, agradeço se compartilhar.

abraços
LUIS.HERRERA 20/01/2014 09:22:35
#433262
Bom dia amigos.
Será que não há como fazer essa ordenação de modo mais simples?

Ninguém implementou ordenação no datagridview ainda?

NILSONTRES 20/01/2014 09:57:57
#433263
Alterou a propriedade AllowUserToOrderColluns para True ?
LUIS.HERRERA 20/01/2014 10:33:41
#433265
Nilson eu coloquei sim, inclusive como o grid é sempre recriado (colunas) via código a cada carregamento, uma vez que se associa um List a ele, eu inclui essa instrução também no grid_DataBindingComplete para forçar que seja ativada, depois de completar o carregamento, mas em nenhuma das duas opções funciona.

Eu uso os seguintes métodos, não sei se pode estar causando algum conflito, mas não deveria:


//Aqui monto o grid via código, a cada pesquisa.
public void MontaGrid()
{
grid.DataSource = null;
grid.Columns.Clear();

// criando as colunas
grid.Columns.Add([Ô]ID[Ô], [Ô]Código[Ô]);
grid.Columns[0].DataPropertyName = [Ô]ID[Ô];
grid.Columns[0].Visible = false;
grid.Columns.Add([Ô]ID_EMPRESA[Ô], [Ô]ID Empresa[Ô]);
grid.Columns[1].DataPropertyName = [Ô]ID_EMPRESA[Ô];
grid.Columns[1].Visible = false;
grid.Columns.Add([Ô]DEPTO[Ô], [Ô]Departamento[Ô]);
grid.Columns[2].DataPropertyName = [Ô]DEPTO[Ô];
grid.Columns[2].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
grid.Columns[2].Width = 125;
grid.Columns[2].DividerWidth = 1;
grid.Columns[2].Visible = true;
grid.Columns.Add([Ô]ID_CHEFE[Ô], [Ô]Código do Chefe[Ô]);
grid.Columns[3].DataPropertyName = [Ô]ID_CHEFE[Ô];
grid.Columns[3].Visible = false;
grid.Columns.Add([Ô]NOME[Ô], [Ô]Nome do Chefe[Ô]);
grid.Columns[4].DataPropertyName = [Ô]NOME[Ô];
grid.Columns[4].Visible = false;
grid.Columns.Add([Ô]INATIVO[Ô], [Ô]Situação[Ô]);
grid.Columns[5].DataPropertyName = [Ô]INATIVO[Ô];
grid.Columns[5].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
grid.Columns[5].Width = 50;
grid.Columns[5].DividerWidth = 1;
grid.Columns[5].Visible = true;
grid.Columns.Add([Ô]RAZAOSOCIAL[Ô], [Ô]Razão Social[Ô]);
grid.Columns[6].DataPropertyName = [Ô]RAZAOSOCIAL[Ô];
grid.Columns[6].Visible = false;
grid.Refresh();
[txt-color=#e80000]grid.AllowUserToOrderColumns = true; [/txt-color] // tentei aqui e também não resolver
}

private void grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
// aqui formato o conteúdo de um campo, trocando seu valor numérico com (branco ou X) em função do conteúdo no banco.
if (e.ColumnIndex == grid.Columns[[Ô]INATIVO[Ô]].Index)
{
e.Value = (e.Value.ToString() == 0.ToString() ? string.Empty : [Ô]X[Ô]); //aqui pega o valor como 0 = byte
}
}

private void grid_KeyDown(object sender, KeyEventArgs e) //-> evento disparado ao terminar de pressionar uma tecla
{
if (grid.CurrentRow == null) //-> testar se há linha/registro selecionado no grid
return;

if (e.KeyCode == Keys.Enter) //-> testar se a tecla é ENTER (seleção do registro pelo usuário)
{
grid_Click(grid, new EventArgs()); //-> crio um novo evento click simulando o click no grid para que o item selecionado pela setinha teclado seja realçado no grid.

// seta linha correta selecionada para corrigir erro da tecla ENTER que pula uma linha pra frente
e.SuppressKeyPress = true;
return;
}

if (e.KeyCode == Keys.Down)
{
grid.DefaultCellStyle.SelectionBackColor = corfundo; //-> coloca cor padrão da seleção de uma linha
grid.DefaultCellStyle.SelectionForeColor = corfonte;
return;
}

if (e.KeyCode == Keys.Up)
{
grid.DefaultCellStyle.SelectionBackColor = corfundo; //-> coloca cor padrão da seleção de uma linha
grid.DefaultCellStyle.SelectionForeColor = corfonte;
return;
}
}

private void grid_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
// Evento que ocorre após carregar o grid pelo DataSource, assim eu tiro a seleção do primeiro registro no grid.
// Nota: Se não fizesse assim, sempre ao terminar o carregamento a última linha vinha selecionada e não desejo isso.
DataGridView grid;
grid = (DataGridView)sender;
grid.ClearSelection();
LimparCampos(); //aqui eu limpo os campos, pois foram preenchidos pelo evento Change do grid após carregar o DataTable.

[txt-color=#e80000]grid.AllowUserToOrderColumns = true; [/txt-color] // também tentei aqui e nada
}

private void grid_Click(object sender, EventArgs e) //-> usado evento para selecionar registro do grid/povoar campos no form e evitar erros gerados por outros eventos
{
if (grid.CurrentRow == null)
return;

// se houver seleção de registro no grid, povoa os campos.
txtID.Text = grid.CurrentRow.Cells[[Ô]ID[Ô]].Value.ToString();
.....

// Define a cor da seleção de um registro no grid, para ficar diferente do zebrado.
grid.DefaultCellStyle.SelectionBackColor = Color.Red;
grid.DefaultCellStyle.SelectionForeColor = Color.White;

}
}


Nota: Estou usando o C# 2008, será que há algum bug nele? Tem todas as atualizações que foram disponibilizadas pelo Windows Update.

realmente não sei o que pode ser, testei em alguns forms diferentes e nenhum funciona.

Alguma outra ideia???
LUIS.HERRERA 20/01/2014 12:12:44
#433270
Bem amigos, pesquisando muito, mas muito mais, descobri que a ordenação no DataGridView não funciona se usar o preenchimento programaticamente do DataSource. Neste caso tem que se criar métodos / funções específicas para ordenar seus dados.

A propriedade AllUserToOrderColums só funciona para dados da coleção Itens do componente ou se o banco estiver vinculado ao grid.

Bem então a solução que encontrei e deixo aqui se alguém precisar, foi usar um switch n evento ColumnHeaderMouseClick do grid que faz a ordenação, tem que definir cada coluna que quer ordenar, e usar uma variável estática auxiliar para cada coluna, a fim de marcar se a última ordenação foi ascendente ou descendente.

Nota: Não sei se funciona com Datas, pois não testei.

        private void grid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
List<InstrutoresModelo> instrutor = grid.DataSource as List<InstrutoresModelo>;

switch (grid.Columns[e.ColumnIndex].Name)
{
case [Ô]Nome[Ô]:
colunaNome = colunaNome == [Ô]Ascendente[Ô] ? [Ô]Descendente[Ô] : [Ô]Ascendente[Ô];
if (colunaNome == [Ô]Ascendente[Ô])
instrutor = instrutor.OrderBy(c => c.Nome.Trim()).ToList();
else
instrutor = instrutor.OrderByDescending(c => c.Nome.Trim()).ToList();
break;
case [Ô]ID[Ô]:
colunaID = colunaID == [Ô]Ascendente[Ô] ? [Ô]Descendente[Ô] : [Ô]Ascendente[Ô];
if (colunaID == [Ô]Ascendente[Ô])
instrutor = instrutor.OrderBy(c => c.ID).ToList();
else
instrutor = instrutor.OrderByDescending(c => c.ID).ToList();
break;
}

grid.DataSource = instrutor;
}


Espero que ajude. Vou deixar o tópico aberto só mais alguns dias, pois pode aparecer alguém com uma solução melhor.

IMPORTANTE: Quando postarem uma dúvida e descobrirem como resolver, não feche o post apenas dizendo....[Ô]Já resolvi obrigado[Ô], mas coloque a solução para que outros possam usar se necessário.
NILSONTRES 20/01/2014 18:07:26
#433295
Por isso que apesar de muitos condenarem, preencho minhas dezenas ou centenas de datagrids que tenho, tudo na unha, assim não tenho nenhum tipo de limitação, me irritava muito preenchendo via datasource, porque era muito cheio de frescura a manipulação.
E em testes que fiz, a diferença no desempenho é muito pequena, não vale a pena.
LUIS.HERRERA 21/01/2014 08:35:11
#433307
Nossa Nilson, mas ficar reinventando a roda não tem lógica. O problema aqui talvez seja exatamente eu não conhecer 100% dos recursos da linguagem, ou como exatamente fazer, mas fazer na mão isso você acaba perdendo outros benefícios da linguagem também. Vou testar o código do Ocelot para ver se resolve.

Na realidade perdi o benefício do Order do grid, mas tenho todos os outros recursos que não teria fazendo eu mesmo o preenchimento como Cast. Além disso, continuo com tudo que o List<T> oferece e não teria, assim basta fazer cast e usar os métodos do List, sem ter que escrever nenhuma linha de código (recriar a roda novamente).

Bem gosto é gosto. Valeu sua participação.
NILSONTRES 21/01/2014 09:37:51
#433314
Citação:

Bem gosto é gosto. Valeu sua participação.


Muito bem colocado.

Abraço.

Tópico encerrado , respostas não são mais permitidas