简体   繁体   中英

How do you automatically resize columns in a DataGridView control AND allow the user to resize the columns on that same grid?

I am populating a DataGridView control on a Windows Form (C# 2.0 not WPF).

My goal is to display a grid that neatly fills all available width with cells - ie no unused (dark grey) areas down the right and sizes each column appropriately according to the data it contains, also allows the user to resize any of the columns to their liking.也允许用户调整任何列的大小随心所欲。

I am attempting to achieve this by setting the AutoSizeMode of each column to be DataGridViewAutoSizeColumnMode.AllCells except for one of the columns which I set to DataGridViewAutoSizeColumnMode.Fill in order to ensure the entire area of the grid is neatly filled with data. (I don't mind that when the user attempt to resize this column it springs back to a size that ensures the horizontal space is always used.)

However, as I mentioned, once loaded I would like to allow the user to resize the columns to suit their own requirements - in setting these AutoSizeMode values for each column it appears the user is then unable to then resize those columns.

I've tried not setting the AutoSizeMode of all the columns which does allow resizing BUT doesn't set the initial size according to the data the cells contain. The same result occurs when changing the grid's AutoSizeMode back to "Not Set" after loading the data.

Is there a setting I'm missing here which allows automatic setting of default column widths AND user resizing or is there another technique I must use when populating the DataGridView control?

This trick works for me:

    grd.DataSource = DT;

    // Set your desired AutoSize Mode:
    grd.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
    grd.Columns[1].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
    grd.Columns[2].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

    // Now that DataGridView has calculated it's Widths; we can now store each column Width values.
    for (int i = 0; i <= grd.Columns.Count - 1; i++)
    {
        // Store Auto Sized Widths:
        int colw = grd.Columns[i].Width;

        // Remove AutoSizing:
        grd.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;

        // Set Width to calculated AutoSize value:
        grd.Columns[i].Width = colw;
    }

In the Code above: You set the Columns AutoSize Property to whathever AutoSizeMode you need. Then (Column by Column) you store each column Width value (from AutoSize value); Disable the AutoSize Property and finally, set the Column Width to the Width value you previously stored.

Maybe you could call

dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.Fill);

After setting datasource. It will set the width and allow resize.

More on MSDN DataGridView.AutoResizeColumns Method (DataGridViewAutoSizeColumnsMode) .

AC# version of Miroslav Zadravec's code

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;
}

Posted as Community Wiki so as to not mooch off of the reputation of others

In my application I have set

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

Also, I have set the

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

Now the column widths can be changed and the columns can be rearranged by the user. That works pretty well for me.

Maybe that will work for you.

After adding the data to the grid add the following code which will adjust the column according to the length of data in each cell

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

Here is the Result

在此处输入图片说明

Well, I did this like this:

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

in that particular order. Columns are resized (extended) AND the user can resize columns afterwards.

A simple two lines of code works for me.

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

If I understood the question correctly there should be an easier way to accomplish what you need. Call dgvSomeDataGrid.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);

That should do the trick. However, there is one pitfall as you cannot simply call this method directly after populating your DataGridView control. Instead you will have to add an EventHandler for the VisibleChanged event and call the method in there.

Resume of the question:
Have column width adapt to the content (with different method across the column),
but then allow the user to set the column width...

Developing from Miroslav Zadravec's answer , for me what worked was immediately using the auto computed column.Width to set... 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

This is tested to work when the DataGridView is already created, using a trick like this .

这对我来说很神奇:

dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);

This autofits all columns according to their content, fills the remaining empty space by stretching a specified column and prevents the 'jumping' behaviour by setting the last column to fill for any future resizing.

// 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;

Slightly neater C# code from Miroslav Zadravec's code assuming all columns are to be autosized

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;
}

dataGridView1.AutoResizeColumns();

Another version of Miroslav Zadravec's code, but slightly more automated and 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;
        }
    }

I put second part into separate event, because I fill datagridvew in initialization of form and if both parts are there, nothing is changing, because probably autosize calculates widths after datagridview is displayed, so the widths are still default in Form1() method. After finishing this method, autosize does its trick and immediately after that (when form is shown) we can set the widths by second part of the code (here in Form1Shown event). This is working for me like a charm.

Here's a simplified code for Miroslav Zadravec's answer in 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;

A little improvement from Schnapple's version

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;
}

The column widths set to fit its content I have used the bellow statement, It resolved my issue.

First Step :

RadGridViewName.AutoSize = true;

Second Step :

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

Third Step :

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; 
}
foreach (DataGridViewColumn c in dataGridView.Columns)
    c.Width = c.GetPreferredWidth(DataGridViewAutoSizeColumnMode.AllCells, true);

This should work whether the dataGridView has been displayed or not (ie even if called from the class constructor).

The same method, but with DataGridViewAutoSizeColumnMode.DisplayedCells , fails in the above case for the obvious reason - no cell has been displayed yet! For some non-obvious reason, AutoResizeColumns also fails in this case.

Did you try to set up the FillWeight property of your DataGridViewColumns object?

For example:

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

I think it should work in your case.

If you bind your datasource to a datatable for example, you need to set the properties after the binding is done:

        private void dgv_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
            dgv.AutoResizeColumns();
            dgv.AllowUserToResizeColumns = true;
        }
  • Thanks for the solution above (To iterate through the DataGridView.Columns , change AutoSizeMode to a valid one, collect width value and set it back after change AutoSizeMode to DataGridViewAutoSizeColumnMode.None ).
  • I struggled with it, and noticed it won't work whenever it is called from the class constructor or any line before Form.Show() or Form.ShowDialog() . So I put this code snippet in the Form.Shown event and this works for me.
  • My transformed code, reguardless of whatever DataGridView.AutoSizeColumnsMode set before, I use DataGridViewColumn.GetPreferredWidth() instead of changing DataGridViewColumn.AutoSizeMode and set the width value immediately, then change DataGridView.AutoSizeColumnsMode once:

     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; }
  • Be sure to set

     dataGridView.AllowUserToResizeColumns = true;
  • I don't know how come this only works after the form is shown.

I had to do this in VB and prefer to split it out to a method that I placed in a Module. You can add the Fill column as another ByRef parameter if desired.

''' <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

You could do something like this:

   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;

All columns will adapt to the content except the last one will fill the grid.

With $array being the contents of a PSCustomObject, this works:

$dataGridView1.DataSource=[collections.arraylist]($array)
$dataGridView1.Columns | Foreach-Object{$_.AutoSizeMode = [System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM