Reputation: 9464
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 - i.e. no unused (dark grey) areas down the right and sizes each column appropriately according to the data it contains, but 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?
Upvotes: 135
Views: 381121
Reputation: 4665
// Created By [email protected] at 2024-11-01 10:36:30+0800
using System.ComponentModel;
ApplicationConfiguration.Initialize();
var persons = new BindingList<Person>();
var dataGridView = new DataGridView { Dock = DockStyle.Fill, AllowUserToAddRows = false, DataSource = persons };
dataGridView.DataBindingComplete += delegate
{
if (dataGridView.Tag != null) return;
var columns = dataGridView.Columns.OfType<DataGridViewColumn>().ToList();
foreach (var column in columns) column.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
if (dataGridView.RowCount == 0) return;
dataGridView.Tag = new object();
foreach (var column in columns) column.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
columns[^1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridView.AutoResizeColumns();
ThreadPool.QueueUserWorkItem(delegate
{
dataGridView.Invoke(delegate
{
foreach (var column in columns.Where(column => column.AutoSizeMode != DataGridViewAutoSizeColumnMode.Fill))
{
column.Width = column.Width;
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
}
});
});
};
var form = new Form();
form.Size = new Size(300, 200);
form.Controls.Add(dataGridView);
form.Load += delegate
{
persons.Add(new Person { Id = 3, Name = "Gamma Gamma Gamma Gamma Gamma" });
persons.Add(new Person { Id = 1, Name = "Alpha" });
persons.Add(new Person { Id = 2, Name = "Beta Beta Beta" });
};
Application.Run(form);
internal class Person
{
public long Id { get; set; }
public string Name { get; set; }
}
Upvotes: 0
Reputation: 3740
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 whatever 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.
Upvotes: 172
Reputation: 16
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}
Upvotes: 0
Reputation: 5222
A simple two lines of code works for me.
dataGridView.DataSource = dataTable;
dataGridView.AutoResizeColumns();
Upvotes: 11
Reputation: 440
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.
Upvotes: 0
Reputation: 131
This did wonders for me:
dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
Upvotes: 4
Reputation: 173
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
Upvotes: 0
Reputation: 1533
foreach (DataGridViewColumn c in dataGridView.Columns)
c.Width = c.GetPreferredWidth(DataGridViewAutoSizeColumnMode.AllCells, true);
This should work whether the dataGridView
has been displayed or not (i.e. 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.
Upvotes: 1
Reputation: 29
DataGridView.Columns
, change AutoSizeMode
to a valid one, collect width value and set it back after change AutoSizeMode
to DataGridViewAutoSizeColumnMode.None
). 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.
Upvotes: 0
Reputation: 21
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;
Upvotes: 2
Reputation: 81
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.
Upvotes: 2
Reputation: 35554
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.
Upvotes: 23
Reputation: 12918
A C# 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
Upvotes: 34
Reputation: 3480
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;
}
Upvotes: 0
Reputation: 20326
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.
Upvotes: 5
Reputation: 21391
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
Upvotes: 21
Reputation: 7856
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.
Upvotes: 6
Reputation: 91
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;
}
Upvotes: 2
Reputation: 549
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;
Upvotes: 4
Reputation: 11
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;
}
Upvotes: 1
Reputation: 2472
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;
}
Upvotes: 2
Reputation: 607
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).
Upvotes: 51
Reputation: 11
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.
Upvotes: 1
Reputation: 151
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.
Upvotes: 12