8

I have a method to create DataGridView dynamically but when it is shown up, the width is greater than the content width (total width of the columns). Also the height has not enough length to meet the length of the rows.

I tried using this method but it didn't work:

    DataGridView CreateInputBox(int proc, int mac)
        {
            DataGridView databox = new DataGridView();
            for (int i = 0; i < mac; i++)
            {
                databox.Columns.Add("col" + (i + 1), "M" + (i + 1));
                databox.Columns[i].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
                databox.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable;
            }
            databox.RowTemplate.DefaultHeaderCellType = typeof(CustomHeaderCell);
            databox.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
            databox.RowHeadersDefaultCellStyle.Padding = new Padding(2);
            for (int i = 0; i < proc; i++)
            {
                databox.Rows.Add();
                databox.Rows[i].HeaderCell.Value = "P" + (i + 1);
            }
            databox.DefaultCellStyle.SelectionBackColor = Color.LightGray;
            databox.AllowUserToAddRows = false;
            databox.AllowUserToDeleteRows = false;
            databox.AllowUserToOrderColumns = false;
            databox.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
            databox.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;

            //This block doesn't work
            var totalHeight = databox.Rows.GetRowsHeight(DataGridViewElementStates.None);
            var totalWidth = databox.Columns.GetColumnsWidth(DataGridViewElementStates.None);
            databox.Width = totalWidth;
            databox.Height = totalHeight;
            //
            return databox;
        }
    public class CustomHeaderCell : DataGridViewRowHeaderCell
    {
        protected override Size GetPreferredSize(Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex, Size constraintSize)
        {
            var size1 = base.GetPreferredSize(graphics, cellStyle, rowIndex, constraintSize);
            var value = string.Format("{0}", this.DataGridView.Rows[rowIndex].HeaderCell.FormattedValue);
            var size2 = TextRenderer.MeasureText(value, cellStyle.Font);
            var padding = cellStyle.Padding;
            return new Size(size2.Width + padding.Left + padding.Right, size1.Height);
        }
        protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, DataGridViewPaintParts.Background);
            base.PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
            TextRenderer.DrawText(graphics, string.Format("{0}", formattedValue), cellStyle.Font, cellBounds, cellStyle.ForeColor);
        }
    }

Result:

enter image description here

As you can see the width of the DataGridView control is so long. How can I fit it for both dimension?

Ali Tor
  • 2,772
  • 2
  • 27
  • 58
  • 4
    Possible duplicate of [DataGridView AutoFit and Fill](http://stackoverflow.com/questions/18666582/datagridview-autofit-and-fill) – isxaker Jun 06 '16 at 15:47
  • What is `CustomHeaderCell` ? – TaW Jun 06 '16 at 15:51
  • It is a class to autofit the row header container to its content text. I got it from http://stackoverflow.com/questions/37647662/why-doesnt-autoresize-work-for-row-header-width-in-datagridview-in-c which is my another question. I updated the question adding the CustomHeaderCell. – Ali Tor Jun 06 '16 at 16:04
  • 2
    @isxaker I don't think it is the same question with this. The question you gave is about the column autosize , but my question about DataGridView's own (container). – Ali Tor Jun 06 '16 at 16:09
  • Ah. I have updated the screenshot to show the result when including the CustomHeaderCell class.. – TaW Jun 06 '16 at 16:40
  • I see. It is just a small detail, not much important. Thanks again @TaW. – Ali Tor Jun 06 '16 at 16:47

2 Answers2

20

The main problem is that your newly created DataGridView has not finished its internal layout before being added to a parent container and will still report all columns as having a width = 100.

One way to fix it is to call a sizing function after the DGV has been displayed:

void sizeDGV(DataGridView dgv)
{
    DataGridViewElementStates states = DataGridViewElementStates.None;
    dgv.ScrollBars = ScrollBars.None;
    var totalHeight = dgv.Rows.GetRowsHeight(states) + dgv.ColumnHeadersHeight;
    totalHeight += dgv.Rows.Count * 4  // a correction I need
    var totalWidth = dgv.Columns.GetColumnsWidth(states) + dgv.RowHeadersWidth;
    dgv.ClientSize = new Size(totalWidth , totalHeight );
}

enter image description here

Note that I have fixed a few things along the way:

  • Both width and height did not include the headers
  • changing the outer size ignores the border. I change the ClientSize instead.
  • Before the size can work we need to switch off the scroll bars.
TaW
  • 53,122
  • 8
  • 69
  • 111
  • It works fine. You are rigth about the sizing can be done only after the `DataGridView` has been displayed. I tried the `sizeDVG` function in the `Load` event instead of constructor of the `Form` and it worked. Thanks. – Ali Tor Jun 06 '16 at 16:43
  • 1
    Actually (at least) the height is off a little. I think one has to add something like Rows.Count * 4. It shows when adding a lot of rows. Here the row.height is given as 21 but actually has 24 plus 1 pixel for a cell border.. – TaW Jun 06 '16 at 16:50
1

Just use

dataGridView1.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

Full code:

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public Form1()
{
    InitializeComponent();

    List<Person> persons = new List<Person> {new Person() {ID = 0, Name = "one"}, new Person() {ID = 1, Name = "two"}, new Person() {ID = 2, Name = "tree"}, new Person() {ID = 3, Name = "four"}};
    dataGridView1.DataSource = persons;
    dataGridView1.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; 
}

private System.Windows.Forms.DataGridView dataGridView1;
private void InitializeComponent()
{
    this.dataGridView1 = new System.Windows.Forms.DataGridView();
    ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
    this.SuspendLayout();
    // 
    // dataGridView1
    // 
    this.dataGridView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
    this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
    this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
    this.dataGridView1.Location = new System.Drawing.Point(0, 0);
    this.dataGridView1.Name = "dataGridView1";
    this.dataGridView1.Size = new System.Drawing.Size(284, 262);
    this.dataGridView1.TabIndex = 0;
    // 
    // Form1
    // 
    this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.ClientSize = new System.Drawing.Size(284, 262);
    this.Controls.Add(this.dataGridView1);
    this.Name = "Form1";
    this.Text = "Form1";
    ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
    this.ResumeLayout(false);

}

enter image description here

isxaker
  • 8,446
  • 12
  • 60
  • 87
  • 1
    In your solution the columns are sizable depending on the containers' width, but in my question the columns are depending on the text content width. I mean I don't need to change the columns width, just the containers'. So this answer is not good for me. Thanks for your efforts in anyway @isxaker. – Ali Tor Jun 06 '16 at 16:53
  • I have added this line ( dataGridView1.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill; ) after adding a list into my DataGridView. It working like a charm. – Rahmat Ali Sep 23 '18 at 12:22