Como você redimensiona automaticamente as colunas em um controle DataGridView E permite que o usuário redimensione as colunas na mesma grade?


109

Estou preenchendo um controle DataGridView em um Windows Form (C # 2.0 não WPF).

Meu objetivo é exibir uma grade que preencha perfeitamente toda a largura disponível com células - ou seja, sem áreas não utilizadas (cinza escuro) à direita e dimensiona cada coluna apropriadamente de acordo com os dados que ela contém, mas também permite ao usuário redimensionar qualquer uma das colunas ao seu gosto.

Estou tentando fazer isso definindo o AutoSizeMode de cada coluna como DataGridViewAutoSizeColumnMode.AllCells, exceto por uma das colunas que defini como DataGridViewAutoSizeColumnMode.Fill para garantir que toda a área da grade seja perfeitamente preenchida com dados. (Não me importo que quando o usuário tenta redimensionar esta coluna ela volta para um tamanho que garante que o espaço horizontal seja sempre usado.)

No entanto, como mencionei, uma vez carregado, gostaria de permitir que o usuário redimensione as colunas de acordo com seus próprios requisitos - ao definir esses valores de AutoSizeMode para cada coluna, parece que o usuário não consegue redimensionar essas colunas.

Eu tentei não definir o AutoSizeMode de todas as colunas, o que permite o redimensionamento, mas não define o tamanho inicial de acordo com os dados que as células contêm. O mesmo resultado ocorre ao alterar o AutoSizeMode da grade de volta para "Not Set" após carregar os dados.

Existe uma configuração que estou faltando aqui que permite a configuração automática de larguras de coluna padrão E redimensionamento do usuário ou há outra técnica que devo usar ao preencher o controle DataGridView?


não defina como "Não definido" defina como "Nenhum" para que o redimensionamento não seja revertido Voltar - testado para c #, .net2.0
bh_earth0

Respostas:


132

Este truque funciona para mim:

grd.DataSource = DT;

//set autosize mode
grd.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
grd.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
grd.Columns[2].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

//datagrid has calculated it's widths so we can store them
for (int i = 0; i <= grd.Columns.Count - 1; i++) {
    //store autosized widths
    int colw = grd.Columns[i].Width;
    //remove autosizing
    grd.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
    //set width to calculated by autosize
    grd.Columns[i].Width = colw;
}

O que acontece aqui é que você configura o tamanho automático para o modo que você precisa e, em seguida, coluna por coluna, você armazena a largura obtida no cálculo do tamanho automático, remove o dimensionamento automático e define a largura para o valor armazenado antes.


1
Coloquei um código semelhante em uma rotina chamada AutoResizeColumnWidthsYetAllowUserResizing. É chamado depois que a grade é preenchida inicialmente e também depois que o usuário edita os dados (ou seja, do evento CellEndEdit da grade).
DeveloperDan

5
Este é um ótimo código. Precisa ser colocado no evento 'DataGridView1_DataSourceChanged'.
user890332

1
Parece-me que fazer grd.Columns(i).Width = grd.Columns(i).Widthjá funcionará. Veja aqui .
Antonio

2
para c # semelhante, mas com colchetes dataGridView1.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
barlop

Isso pode ter chegado muito tarde, mas alguma chance ou maneira, poderíamos redimensionar com base no conteúdo de uma linha específica? Vamos dizer, com base no conteúdo das células na primeira linha, independentemente da largura das células nas outras linhas.
Murtuza Husain

45

Talvez você pudesse ligar

dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.Fill);

Depois de definir a fonte de dados. Irá definir a largura e permitir o redimensionamento.

Mais sobre MSDN DataGridView.AutoResizeColumns Method (DataGridViewAutoSizeColumnsMode) .


2
Não sei por que essa resposta não está recebendo mais atenção. Muito mais limpo. Embora, se você estiver procurando corresponder à largura do conteúdo da célula, DataGridViewAutoSizeColumnsMode.AllCells funcione um pouco melhor.
iwalkbarefoot de

31
usando esta solução, recebo o próximo erro: "O parâmetro autoSizeColumnMode não é válido para esta operação. Não pode ser NotSet, None ou Fill, mas precisa indicar um critério de dimensionamento." . Acabei usando este dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
itsho

6
Usar DataGridViewAutoSizeColumnMode.Fill não funciona porque ignora o conteúdo da célula ao dimensionar colunas.
Stuart Helwig

Eu usei esse método com DataGridViewAutoSizeColumnsMode.DisplayedCells. Além disso, no Forms Designer, o AutoSizeColumnsMode é definido como Nenhum. Eu precisava executar essa chamada de método no manipulador de eventos DataBindingComplete de DataGridView, para garantir que ele sempre (re) dimensionasse corretamente.
Daan

7
Eu não entendo todos os votos positivos ... Isso não funciona, a documentação do MSDN é clara, fazer isso leva a uma ArgumentException se o autoSizeColumnsMode tiver o valor None ou Fill.
Larry

31

Versão AC # do código de Miroslav Zadravec

for (int i = 0; i < dataGridView1.Columns.Count-1; i++)
{
    dataGridView1.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
}
dataGridView1.Columns[dataGridView1.Columns.Count - 1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

for (int i = 0; i < dataGridView1.Columns.Count; i++)
{
    int colw = dataGridView1.Columns[i].Width;
    dataGridView1.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
    dataGridView1.Columns[i].Width = colw;
}

Postado como Community Wiki para não roubar a reputação de terceiros


15

Em meu aplicativo eu configurei

grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
grid.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;

Além disso, eu configurei o

grid.AllowUserToOrderColumns = true;
grid.AllowUserToResizeColumns = true;

Agora, as larguras das colunas podem ser alteradas e as colunas podem ser reorganizadas pelo usuário. Isso funciona muito bem para mim.

Talvez isso funcione para você.


Definir o AutoSizeColumnsMode da grade como "Preencher" parece definir todas as colunas com as mesmas larguras. Sim, as colunas são redimensionáveis, mas as larguras iniciais estão todas erradas. Posso precisar definir as larguras das colunas no código "manualmente".
Stuart Helwig

DV- grid.AutoSizeColumnsMode = DataGridViewAutoSizeColumn-> s <- Mode.Fill; (você perdeu o s, é ColumsMode do lado esquerdo e do lado direito, então essa linha sua não compila) O código para fazer com que o datagridview seja dimensionado automaticamente já é muito chato, então verifique sua resposta primeiro . É a primeira linha que você escreveu e está errada.
barlop

@barlop obrigado pela sua resposta. Você tem o privilégio de editar perguntas e respostas. Se você detectar um erro no meu código, sinta-se à vontade para editar.
Jehof

12

Depois de adicionar os dados à grade adicione o seguinte código que irá ajustar a coluna de acordo com o comprimento dos dados em cada célula

dataGrid1.AutoResizeColumns();            
dataGrid1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;

Aqui está o resultado

insira a descrição da imagem aqui


9

Bem, eu fiz assim:

dgvReport.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
dgvReport.AutoResizeColumns();
dgvReport.AllowUserToResizeColumns = true;
dgvReport.AllowUserToOrderColumns = true;

nessa ordem particular. As colunas são redimensionadas (estendidas) E o usuário pode redimensionar as colunas posteriormente.


6

Se entendi a pergunta corretamente, deve haver uma maneira mais fácil de realizar o que você precisa. Ligar dgvSomeDataGrid.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);

Isso deve funcionar. No entanto, há uma armadilha, pois você não pode simplesmente chamar esse método diretamente após preencher seu controle DataGridView. Em vez disso, você terá que adicionar um EventHandler para o evento VisibleChanged e chamar o método lá.


1
Isso redimensionaria as colunas de acordo com o conteúdo, mas não garantiria que todo o espaço de grade disponível fosse usado. Ou seja, não "preenche" o espaço restante, se houver.
Stuart Helwig

5

Duas linhas de código simples funcionam para mim.

dataGridView.DataSource = dataTable;
dataGridView.AutoResizeColumns();

4

Resumo da pergunta:
adapte a largura da coluna ao conteúdo (com métodos diferentes na coluna),
mas permita que o usuário defina a largura da coluna ...

Desenvolvendo a partir da resposta de Miroslav Zadravec , para mim o que funcionou imediatamente foi usar o auto computado column.Widthpara definir ... column.Width!

foreach (DataGridViewColumn column in dataGridView.Columns)
{
    if (/*It's not your special column*/)
    {
        column.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
        column.Width = column.Width; //This is important, otherwise the following line will nullify your previous command
        column.AutoSizeMode = DataGridViewAutoSizeColumnMode.NotSet;
    }
}

//Now do the same using Fill instead of AllCells for your special column

Isso é testado para funcionar quando o DataGridViewjá está criado, usando um truque como este .


Eu prefiro usar um foreach como seu código faz. Torna-se mais legível quando você não tem nenhuma matemática no início do loop. Eu fiz assim, e o "column.Width = column.Width;" é interessante.
Greg Barth

4

Isso fez maravilhas para mim:

dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);

1
Solução simples!
Mark Kram

1
Funcionou para mim apenas se definido como Nenhum posteriormente, ou seja,dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
Faça novo em

3

Isso ajusta automaticamente todas as colunas de acordo com seu conteúdo, preenche o espaço vazio restante ao esticar uma coluna especificada e evita o comportamento de 'salto', definindo a última coluna para preencher para qualquer redimensionamento futuro.

// autosize all columns according to their content
dgv.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
// make column 1 (or whatever) fill the empty space
dgv.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
// remove column 1 autosizing to prevent 'jumping' behaviour
dgv.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
// let the last column fill the empty space when the grid or any column is resized (more natural/expected behaviour) 
dgv.Columns.GetLastColumn(DataGridViewElementStates.None, DataGridViewElementStates.None).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

Sei que é uma resposta antiga, mas funciona bem, mesmo quando o número de colunas não é conhecido com antecedência.
Nilo Paim

2

Código C # ligeiramente mais puro do código de Miroslav Zadravec, assumindo que todas as colunas devem ser dimensionadas automaticamente

for (int i = 0; i < dgvProblems.Columns.Count; i++)
{
    dgvProblems.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
    int colw = dgvProblems.Columns[i].Width;
    dgvProblems.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
    dgvProblems.Columns[i].Width = colw;
}

2

Outra versão do código de Miroslav Zadravec, mas um pouco mais automatizada e universal:

    public Form1()
    {
        InitializeComponent();
        dataGridView1.DataSource = source;
        for (int i = 0; i < dataGridView1.Columns.Count - 1; i++) {
            dataGridView1.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
        }
        dataGridView1.Columns[dataGridView1.Columns.Count].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

    }

    void Form1Shown(object sender, EventArgs e)
    {
        for ( int i = 0; i < dataGridView1.Columns.Count; i++ )
        {
            int colw = dataGridView1.Columns[i].Width;
            dataGridView1.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
            dataGridView1.Columns[i].Width = colw;
        }
    }

Eu coloquei a segunda parte em um evento separado, porque eu preencho a datagridvewinicialização do formulário e se ambas as partes estão lá, nada muda, porque provavelmente autosize calcula larguras depois de datagridviewser exibido, então as larguras ainda são padrão no Form1()método. Depois de terminar este método, autosize faz seu truque e imediatamente depois disso (quando o formulário é mostrado), podemos definir as larguras pela segunda parte do código (aqui no Form1Shownevento). Isso está funcionando para mim como um encanto.


2

Aqui está um código simplificado para a resposta de Miroslav Zadravec em c #:

CurrentDGV.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader;
for (int i = 0; i < dataGridView1.Columns.Count; i++) dataGridView1.Columns[i].Width = dataGridView1.Columns[i].Width;
CurrentDGV.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;

1

Você tentou configurar a FillWeightpropriedade do seu DataGridViewColumnsobjeto?

Por exemplo:

this.grid1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
this.grid1.Columns[0].FillWeight = 1.5;

Acho que deve funcionar no seu caso.


1

Uma pequena melhoria da versão de Schnapple

int nLastColumn = dgv.Columns.Count - 1;
for (int i = 0; i < dgv.Columns.Count; i++)
{
    if (nLastColumn == i)
    {
        dgv.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
    }
    else
    {
        dgv.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
    }
}

for (int i = 0; i < dgv.Columns.Count; i++)
{
    int colw = dgv.Columns[i].Width;
    dgv.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
    dgv.Columns[i].Width = colw;
}


1

As larguras das colunas definidas para caber no seu conteúdo Usei a declaração abaixo, Isso resolveu meu problema.

Primeiro passo :

RadGridViewName.AutoSize = true;

Segundo passo :

// This mode  fit in the header text and column data for all visible rows. 
this.grdSpec.MasterTemplate.BestFitColumns();

Terceiro passo :

for (int i = 0; i < grdSpec.Columns.Count; i++) 
{
    // The column width adjusts to fit the contents all cells in the control.
    grdSpec.Columns[i].AutoSizeMode = BestFitColumnMode.AllCells; 
}

1
foreach (DataGridViewColumn c in dataGridView.Columns)
    c.Width = c.GetPreferredWidth(DataGridViewAutoSizeColumnMode.AllCells, true);

Isso deve funcionar se o dataGridView tenha sido exibido ou não (ou seja, mesmo se chamado a partir do construtor da classe).

O mesmo método, mas com DataGridViewAutoSizeColumnMode.DisplayedCells, falha no caso acima pela razão óbvia - nenhuma célula foi exibida ainda! Por alguma razão não óbvia, AutoResizeColumnstambém falha neste caso.


0

Se você vincular sua fonte de dados a uma tabela de dados, por exemplo, será necessário definir as propriedades após a vinculação:

        private void dgv_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
            dgv.AutoResizeColumns();
            dgv.AllowUserToResizeColumns = true;
        }

0
  • Obrigado pela solução acima (para iterar através do DataGridView.Columns, mude AutoSizeModepara um válido, colete o valor da largura e defina-o de volta após mudar AutoSizeModeparaDataGridViewAutoSizeColumnMode.None ).
  • Lutei com isso e percebi que não funcionaria sempre que fosse chamado do construtor de classe ou qualquer linha anterior Form.Show() ou Form.ShowDialog(). Então, coloquei esse trecho de código no Form.Shownevento e isso funciona para mim.
  • Meu código transformado, independentemente de qualquer DataGridView.AutoSizeColumnsModeconfiguração anterior, eu uso em DataGridViewColumn.GetPreferredWidth()vez de alterar DataGridViewColumn.AutoSizeModee definir o valor da largura imediatamente, em seguida, alteroDataGridView.AutoSizeColumnsMode uma vez:

    private void form_Shown(object sender, EventArgs e)
    {
            foreach (DataGridViewColumn c in dataGridView.Columns)
                c.Width = c.GetPreferredWidth(DataGridViewAutoSizeColumnMode.DisplayedCells, true);
            dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
    }
  • Certifique-se de definir

            dataGridView.AllowUserToResizeColumns = true;
  • Não sei como isso só funciona depois que o formulário é mostrado.


0

Tive que fazer isso em VB e prefiro dividir em um método que coloquei em um Módulo. Você pode adicionar a coluna Preencher como outro parâmetro ByRef, se desejar.

''' <summary>
''' Makes all columns in a DataGridView autosize based on displayed cells,
''' while leaving the column widths user-adjustable.
''' </summary>
''' <param name="dgv">A DataGridView to adjust</param>
Friend Sub MakeAdjustableAutoSizedGridCols(ByRef dgv As DataGridView)
    Dim width As Integer

    For Each col As DataGridViewColumn In dgv.Columns
        col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells
        width = col.Width
        col.AutoSizeMode = DataGridViewAutoSizeColumnMode.None
        col.Width = width
    Next
    dgv.AllowUserToResizeColumns = True
End Sub

0

Você poderia fazer algo assim:

   grd.DataSource = getDataSource();

    if (grd.ColumnCount > 1)
    {
        for (int i = 0; i < grd.ColumnCount-1; i++)
            grd.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;

        grd.Columns[grd.ColumnCount-1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
    }

    if (grd.ColumnCount==1)
        grd.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

Todas as colunas se adaptarão ao conteúdo, exceto a última que preencherá a grade.


0

Com $ array sendo o conteúdo de um PSCustomObject, isso funciona:

$dataGridView1.DataSource=[collections.arraylist]($array)
$dataGridView1.Columns | Foreach-Object{$_.AutoSizeMode = [System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.