Acordeão no DataGridView do Windows Forms

Eu preciso implementar algum tipo de efeito de acordeão em um DataGridView de formulário do Windows. Quando o usuário seleciona uma linha, a linha é expandida para exibir mais algumas informações e, se possível, alguns botões ou outros controles. O problema é que eu não tenho absolutamente nenhuma idéia de como fazer isso. Eu tentei pesquisar na web, mas não encontrei nada que pudesse me levar na direção certa ao criar isso. Espero que alguém possa me dizer como fazer isso? (não precisa ser uma amostra de código)

Eu criei o modelo abaixo para exibir o que quero fazer.

Pensei em ajustar a altura das colunas e replace o método OnPaint. Eu só preciso exibir algum texto na primeira versão. Se isso é possível, seria ótimo. Eu sei que no futuro eu precisaria colocar alguns botões ou outros controles para fazer várias coisas com o item selecionado. Se isso é muito complicado de conseguir, vou pular essa parte por enquanto. Eu sei que eu poderia usar dicas para texto e ter colunas de botão, etc, mas no meu caso, eu preciso fazê-lo como um acordeão.

DataGridView com maquete de acordeão

Melhores cumprimentos Hans Milling …

Isso não é realmente difícil de fazer. A melhor abordagem seria criar um UserControl dedicado e sobrepô-lo no ponto correto.

Para criar espaço para isso basta alterar a Height da Linha, mantendo o controle da linha, para que você possa reverter quando perder a seleção.

Você também terá que decidir se mais de uma linha pode ser expandida e apenas o que o usuário deve fazer para expandir e redefinir a linha.

O UserControl poderia ter uma function displayRowData(DataGridViewRow row) que você poderia chamar de exibir os campos que você está interessado em seus Labels etc.

Você também deve ter um plano sobre como os Buttons devem interagir com o DataGridView .

Se você quiser que apenas uma linha seja expandida de cada vez, você pode criar a UC na frente, tornar o DGV seu Parent e ocultá-lo. Mais tarde, na interação com o usuário, como clicar na linha ou em uma determinada célula, você poderia movê-la para a linha direita e mostrá-la.

Se mais de uma linha puder ser expandida, você precisará criar várias UCs e rastreá-las em uma List .

Aqui está um exemplo mínimo para incentivá-lo ..:

insira a descrição da imagem aqui

 int normalRowHeight = -1; UcRowDisplay display = new UcRowDisplay(); DataGridViewRow selectedRow = null; public Form1() { InitializeComponent(); // create one display object display = new UcRowDisplay(); display.Visible = false; display.Parent = DGV; display.button1Action = someAction; } 

Depois de ter preenchido o DGV

  // store the normal row height normalRowHeight = DGV.Rows[0].Height; 

Você precisa pelo menos desses events:

 private void DGV_SelectionChanged(object sender, EventArgs e) { if (selectedRow != null) selectedRow.Height = normalRowHeight; if (DGV.SelectedRows.Count <= 0) { selectedRow = null; display.Hide(); return; } // assuming multiselect = false selectedRow = DGV.SelectedRows[0]; // assuming ColumnHeader show with the same height as the rows int y = (selectedRow.Index + 1) * normalRowHeight; display.Location = new Point(1, y); // filling out the whole width of the DGV. // maybe you need more, if the DGV is scrolling horizontally // or less if you show a vertical scrollbar.. display.Width = DGV.ClientSize.Width; // make room for the display object selectedRow.Height = display.Height; // tell it to display our row data display.displayRowData(selectedRow); // show the display display.Show(); } private void DGV_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) { // enforce refresh on the display display.Refresh(); } 

Aqui está uma ação de teste acionada pelo botão no object de exibição:

 public void someAction(DataGridViewRow row) { Console.WriteLine(row.Index + " " + row.Cells[2].Value.ToString()); } 

E, claro, você precisa de um UserControl. Aqui está um simples, com duas etiquetas, um botão e uma etiqueta extra para fechar a canvas:

 public partial class UcRowDisplay : UserControl { public UcRowDisplay() { InitializeComponent(); } public delegate void someActionDelegate(DataGridViewRow row); public someActionDelegate button1Action { get; set; } DataGridViewRow myRow = null; public void displayRowData(DataGridViewRow row) { myRow = row; label1.Text = row.Cells[1].Value.ToString(); label2.Text = row.Cells[0].Value.ToString(); rowDisplayBtn1.Text = row.Cells[2].Value.ToString(); } private void rowDisplayBtn1_Click(object sender, EventArgs e) { button1Action(myRow); } private void label_X_Click(object sender, EventArgs e) { myRow.Selected = false; this.Hide(); } } 

Ele contém três Labels e um Button . No Designer, é assim:

insira a descrição da imagem aqui

Note-se que, a fim de tornar um pouco mais fácil para mim eu modifiquei o DGV para

  • não tem RowHeader; Modifique o local se você tiver um.
  • assumiu que o header da coluna tivesse a mesma altura de uma linha.
  • todas as linhas (normais) para ter a mesma altura.
  • defina o DGV para multiselect = false e somente leitura

Atualizar

Aqui está um exemplo rápido de rolagem:

 private void DGV_Scroll(object sender, ScrollEventArgs e) { DGV.PerformLayout(); var ccr = DGV.GetCellDisplayRectangle(0, selectedRow.Index, true); display.Top = ccr.Top + normalRowHeight; // ** display.Visible = (ccr.Top >= 0 && ccr.Height > 0); } 

Isso (**) assume que a linha selecionada deve permanecer visível. O mesmo cálculo deve acontecer no evento SelectionChanged! Cabe a você decidir o que deve acontecer quando ocorre a rolagem horizontal.

Observe que atualizações semelhantes são necessárias quando as linhas são adicionadas ou removidas antes da linha atual. Por isso, deve ser movido para uma function que você chama nessas ocorrências.

    Intereting Posts