DataGridView:编辑时更改编辑控件大小

Posted

技术标签:

【中文标题】DataGridView:编辑时更改编辑控件大小【英文标题】:DataGridView: Change Edit Control size while editing 【发布时间】:2010-10-15 17:43:04 【问题描述】:

DataGridView 中,我希望在编辑单元格时根据字符串长度扩展单元格大小。 Excel 也是如此。

DataGridView中,进入编辑模式时,在单元格位置放置一个DataGridViewTextBoxEditingControl。我试图改变这个控件的边界/大小,但结果只是我想要的大小的短暂闪烁。它直接覆盖了原始的截断方式。

关于如何让它发挥作用的任何想法?

谢谢,

提莫

【问题讨论】:

【参考方案1】:

您希望在键入时调整单元格的大小吗?或者您是否希望在输入文本并按下回车后调整其大小?第二个选项是公平的最简单的。

告诉我。

谢谢

【讨论】:

-1 与其问另一个问题,您可能应该对您描述的两种方式给出答案,或者对问题发表评论。【参考方案2】:

您需要首先覆盖DataGridViewCell.PositionEditingPanel Method。您需要重新定义自己的列类型和自己的单元格类型才能访问此方法。

这里是一个例子,说明如何做到这一点,将编辑面板(拥有编辑控件的那个)的大小乘以 2:

dataGridView1.AutoGenerateColumns = false; // disable columns auto generation

... add all columns

// add your special column
col = new MyColumn();
col.DataPropertyName = "Text"; // bind with the corresponding property
dataGridView1.Columns.Add(col); // add the custom column

... add other columns

public class MyCell : DataGridViewTextBoxCell

    public override Rectangle PositionEditingPanel(Rectangle cellBounds, Rectangle cellClip, DataGridViewCellStyle cellStyle, bool singleVerticalBorderAdded, bool singleHorizontalBorderAdded, bool isFirstDisplayedColumn, bool isFirstDisplayedRow)
    
        cellBounds.Width *= 2;
        cellClip.Width = cellBounds.Width;
        return base.PositionEditingPanel(cellBounds, cellClip, cellStyle, singleVerticalBorderAdded, singleHorizontalBorderAdded, isFirstDisplayedColumn, isFirstDisplayedRow);
    


public class MyColumn : DataGridViewTextBoxColumn

    public MyColumn()
    
        CellTemplate = new MyCell();
    

【讨论】:

【参考方案3】:

这对我有用:

启用KeyPreview表单的属性并将表单的KeyPress事件的主体更改为:

private void Form1_KeyPress(object sender, KeyPressEventArgs e)

            if (e.KeyChar!='\b')   //discard backspace
            
              dataGridView1.Columns[0].Width += 5;  //the column's index or name

            
            else
            
                dataGridView1.Columns[0].Width -= 5;  //for backspase pressing
            

您可以使用e.KeyChar 限制按下的键;

【讨论】:

尽管如此,即使单元格为空或光标位于最左侧,并且该人正在点击后退,单元格(因此可能是整个列)正在缩小。如果 backdelete 不删除字符,它不应该真的缩小【参考方案4】:

这个问题已经很老了,但希望我的回答能帮助别人。我遇到了同样的问题,并且能够使用类似于以下的过程来使列宽在用户键入时动态更新,以确保文本适合列。

使用的事件:

CellBeginEdit CellEndEdit EditingControlShowing TextBoxKeyPressEvent(即KeyPress

注意:以下代码假定AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells

// ---------------------------------------------------------------------------

private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)

    // Copies the original column width because switching to DataGridViewAutoSizeColumnMode.None
    // will automatically make the column a default width.
    int origColumnWidth = dataGridView1.Columns[e.ColumnIndex].Width;

    dataGridView1.Columns[e.ColumnIndex].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;

    // Reverts back to the original width.
    dataGridView1.Columns[e.ColumnIndex].Width = origColumnWidth;


// ---------------------------------------------------------------------------

private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)

    dataGridView1.Columns[e.ColumnIndex].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;


// ---------------------------------------------------------------------------

private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)

    if (e.Control is TextBox)
    
        var tbox = (e.Control as TextBox);

        // De-register the event FIRST so as to avoid multiple assignments (necessary to do this or the event
        // will be called +1 more time each time it's called).
        tbox.KeyPress -= TextBoxKeyPressEvent;
        tbox.KeyPress += TextBoxKeyPressEvent;
    


// ---------------------------------------------------------------------------

private void TextBoxKeyPressEvent(object sender, KeyPressEventArgs e)

    // Gets the text prior to the new character being added.  Appending an arbitrary "0" to the value
    // to account for the missing character when determining appropriate measurements.
    string prevText = dataGridView1.CurrentCell.EditedFormattedValue.ToString() + "0";

    Graphics editControlGraphics = dataGridView1.EditingControl.CreateGraphics();

    // Gets the length of the current text value.
    SizeF stringSize = editControlGraphics.MeasureString(prevText, dataGridView1.EditingControl.Font);

    int widthForString = (int)Math.Round(stringSize.Width, 0);

    // Makes the column width big enough if it's not already.
    if (dataGridView1.CurrentCell.OwningColumn.Width < widthForString)
    
        dataGridView1.CurrentCell.OwningColumn.Width = widthForString;
    

编辑:更新TextBoxKeyPressEvent 逻辑以考虑退格:

private void TextBoxKeyPressEvent(object sender, KeyPressEventArgs e)
        
            string prevText;
            bool wasBackspaced = false;

            // The following logic will either add or remove a character to/from the text string depending if the user typed
            // an additional character or pressed the Backspace key.  At the end of the day, the cell will (at least) be
            // sized to the configured minimum column width or the largest row width in the column because we're using 
            // AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells.
            if (e.KeyChar == Convert.ToChar(Keys.Back))
            
                prevText = dataGridView1.CurrentCell.EditedFormattedValue.ToString();

                if (prevText.Length == 0)
                
                    // Don't try to make it any smaller...
                    return;
                

                // Remove an arbitrary character for determining appropriate measurements.
                prevText = prevText.Remove(prevText.Length - 1);
                wasBackspaced = true;
            
            else
            
                // Gets the text prior to the new character being added.  Appending an arbitrary "0" to the value
                // to account for the missing character when determining appropriate measurements.
                prevText = dataGridView1.CurrentCell.EditedFormattedValue.ToString() + "0";
            

            Graphics editControlGraphics = dataGridView1.EditingControl.CreateGraphics();

            // Gets the length of the current text value.
            SizeF stringSize = editControlGraphics.MeasureString(prevText, dataGridView1.EditingControl.Font);

            int widthForString = (int)Math.Round(stringSize.Width, 0);

            // Makes the column width big, or small, enough if it's not already.
            if (dataGridView1.CurrentCell.OwningColumn.Width < widthForString ||  // 1. Applies when adding text
                (dataGridView1.CurrentCell.OwningColumn.Width > widthForString &&          // ---
                 dataGridView1.CurrentCell.OwningColumn.MinimumWidth < widthForString &&   // 2. Applies when backspacing
                 wasBackspaced))                                                           // ---
            
                dataGridView1.CurrentCell.OwningColumn.Width = widthForString;
            
        

【讨论】:

这有几个问题(a,b,c)。 a) 它只会扩展而不收缩,例如如果我回删除字符,它不会缩小并且应该真正 b) 如果我在单元格内回删除,那么该代码不起作用,它会将回删除视为任何常规字符并将单元格扩展一个字符,当我希望它缩小细胞时。 c) 如果我点击向前删除,那么过程 TextBoxKeyPressEvent 甚至不会触发。所以它不会尝试缩小文本框。 @barlop 你是对的,我的原始示例没有考虑 Backspace 键。我已经用附加代码更新了我的帖子,说明如何处理。我最初是基于这样一个事实,即控件会根据最小宽度属性自动调整列的大小,并且 AutoSizeColumnsMode 设置为“AllCells”,但这仅在提交编辑后发生。根据 C 点,您是对的,必须使用 KeyDown 事件捕获 Delete 键。在这里解释:***.com/questions/8188328/… 好的...可能值得纠正的另一件事是使用dataGridView1.CurrentCell.EditedFormattedValue 可能有点冒险,正如这里提到的***.com/questions/3207777/… 可能更好地使用dataGridView1.EditingControl.Text【参考方案5】:

我已经找到了一些解决方案

一个使用 MeasureString 和一个 datagridview ,另一个创建另一个 datagridview 来确定单元格的正确宽度(如果单元格具有该内容)。另一个(我最新的)用一个 datagridview 管理它并添加和删除一行。

这是使用第二个数据网格视图的那个

在我给我的两列没有数据的表单上绘制一个 datagridview。

代码将创建第二个 datagridview 也有两列没有数据。

当然,提问者遇到的问题是,如果没有自动调整大小的编辑,则不清楚设置列的宽度。此解决方案创建另一个 datagridview(称为 DGVb),这个未添加到表单中。然后它将数据写入 DGVb 中的一个单元格,查看该单元格的宽度,并使用该图作为该图将单元格设置到正确的 DGV 中。

vine 涉及的另一个问题是,将单元格设置为自动调整大小时,您无法以编程方式设置列的宽度,因此您可以在触发 cellbeginedit 事件时放置代码,将自动调整大小设置为无,然后将其放入当 cellendedit 被触发时重新打开,另一件事是因为设置为 none 可能会立即改变列大小,例如启用 autosize 的 column1 可能是 73,然后当您关闭 autosize 时,它​​会变为 100,因此您可以在将 autosize 设置为 none 之前存储大小,然后将 autosize 设置为 none 并将大小设置为原来的大小,这样可以保留不必要的尺寸变化。这就是 Vine 所涵盖的内容。

此代码扩展和缩小列,并且没有使用 backdelete、forward delete 或箭头键的弱点,尽管在撰写本文时,vine 的答案在这些键上存在一些弱点。我使用 TextChanged 来避免这些问题。 (与 keydown 等相反)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace datagridviewexpandcelldynamically_with_second_dgv

    public partial class Form1 : Form
    
        DataGridView dgvtest = new DataGridView();
        //  DataGridView dgvtest;

        public Form1()
        
            InitializeComponent();
        

        private void Form1_Load(object sender, EventArgs e)
        

                dataGridView1.AllowUserToAddRows = false;
                dgvtest.AllowUserToAddRows = false;

                dataGridView1.CellBeginEdit += (object ssender, DataGridViewCellCancelEventArgs ee) =>
                
                    //keep column width as it is for now but just change autosize to none so will be able to manually increase it
                    int origColumnWidth = dataGridView1.Columns[ee.ColumnIndex].Width;
                    dataGridView1.Columns[ee.ColumnIndex].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
                    dataGridView1.Columns[ee.ColumnIndex].Width = origColumnWidth;
                ;

                dataGridView1.CellEndEdit += (object sssender, DataGridViewCellEventArgs eee) =>
                
                    dataGridView1.Columns[eee.ColumnIndex].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                ;

                dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
                dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;

                dgvtest.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
                dgvtest.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;


                dgvtest.Columns.Add("Column1", "Column1");
                dgvtest.Columns.Add("Column2", "Column2");

                dgvtest.Rows.Add(1);
                dataGridView1.Rows.Add(1);

                /*
                Form newfrm = new Form();
                newfrm.Show();
                newfrm.Controls.Add(dgvtest);
                dgvtest.Show();
                */

                //dgvtest.Rows[0].Cells[0].Value = "abc";


        



        private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        

            if (e.Control is TextBox)
            
                var tbox = (e.Control as TextBox);

                // De-register the event FIRST so as to avoid multiple assignments (necessary to do this or the event
                // will be called +1 more time each time it's called).

                tbox.TextChanged -= TextBoxChanged;
                tbox.TextChanged += TextBoxChanged;
                //not KeyDown 'cos the character has not appeared yet in the box. and one would have to check what it was as a parameter, and if it's a backdelete then go back one.. and also forward delete isn't coutned as a keydown.
                //not KeyUp 'cos while yeah the character has at least appeared, there's a delay so if you hold backdelete then only after releasing it will it trigger the procedure, and updating the width of the cell then is a bit late.
                //not KeyPress 'cos has issues of keyup. 

            

        


        private void TextBoxChanged(object sender, EventArgs e)
        


            int colindex = dataGridView1.CurrentCell.ColumnIndex;


            int oldcolwidth = dataGridView1.CurrentCell.Size.Width;
            //string stredit=dataGridView1.CurrentCell.EditedFormattedValue.ToString();
            string stredit=dataGridView1.EditingControl.Text;
            dgvtest.Rows[0].Cells[0].Value = stredit;

            int newcolwidth = dgvtest.Rows[0].Cells[0].Size.Width;

            int headercellsize = dataGridView1.Columns[colindex].HeaderCell.Size.Width;

            // find biggest existing one
            int maxcellincol = headercellsize;

            int tempcelllength = 0;
            for (int i = 0; i < dataGridView1.Rows.Count; i++)
            
                if (dataGridView1.Rows[i].Cells[colindex].Value == null) dataGridView1.Rows[i].Cells[colindex].Value = "";

                //length of all others but not current.
                tempcelllength = dataGridView1.Rows[i].Cells[colindex].Size.Width;

                if (tempcelllength > maxcellincol) maxcellincol = tempcelllength;
            



            int diffcol = newcolwidth - oldcolwidth;

            // new isn't an ideal name.. 'cos it's not made new yet.. and 'cos if it's smaller than the max one then we won't make it the new one.. but it will be the new one if it's bigger than the max.

            // txtdesc.Text = "";
            txtdesc.Text += "newcol\r\n";
            txtdesc.Text += "maxcellincol=" + maxcellincol + "\r\n";


            //if (newcolwidth < maxcellincol)  != even if = then fine.

            dataGridView1.Columns[colindex].Width = newcolwidth;
            dataGridView1.Width += diffcol;

         

    



在键入文本时扩展单元格的想法是相当的 hack.. 但在视觉上似乎比这个替代方案更可取.. 这样做不那么棘手,但看起来不太好,也就是说,只有单元格在 cellbeginedit 上扩大大小,(因此设置为自动调整为无,并将 col 宽度设置为某个大小,如 = 50),并让它缩小到大小 - 自动调整 - 在 cellendit 上)然后我想在 cellendedit 上增加 datagridview 宽度所以它没有滚动条。但是随后 datagridview col 的大小会跳跃,使用起来并不好。

【讨论】:

如果可以以某种方式克隆 datagridview,这可能会有所改进,或者也许下一个最好的方法是使用字体复制值,因为单元格的宽度取决于在列中的所有其他单元格上,它们的数据和字体。这个之所以有效,是因为第二个 datagridview 与第一个具有相同的数据。 实际上可能第二个 datagridview 只需要 2 个单元格.. 一个保存第一个 datagridview 中该 col 的最大值,另一个保存正在编辑的第一个 datagridview 中的单元格值。并且可以将字体设置为第一个datagridview上相应单元格的字体。【参考方案6】:

我在另一个答案中提到我有两个解决方案,这个是 MeasureString 解决方案(与第二个 datagridview 解决方案相反)

任何提及 textbox1-5.text 等。已经评论说它只是为了调试。

此解决方案和其他解决方案不仅会调整您正在编辑的列的大小,还会调整 datagridview 的宽度和表单宽度,但如果您不想要这种行为,您可以轻松地对此进行评论。

我可能应该使用“uses”关键字来创建图形对象,但无论如何。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace datagridviewexpandcelldynamically

    public partial class Form1 : Form
    
        public Form1()
        
            InitializeComponent();
        

        private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        

            int origColumnWidth = dataGridView1.Columns[e.ColumnIndex].Width;

            dataGridView1.Columns[e.ColumnIndex].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;

            dataGridView1.Columns[e.ColumnIndex].Width = origColumnWidth;

            if (dataGridView1.CurrentCell == null) dataGridView1.CurrentCell.Value = "";


        

        private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        
            dataGridView1.Columns[e.ColumnIndex].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
        

        private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        

            if (e.Control is TextBox)
            
                var tbox = (e.Control as TextBox);

                // De-register the event FIRST so as to avoid multiple assignments (necessary to do this or the event
                // will be called +1 more time each time it's called).

                tbox.TextChanged -= TextBoxChanged;
                tbox.TextChanged += TextBoxChanged;

            

        

        private void TextBoxChanged(object sender, EventArgs e)
        

            // try catch is helpful in a winforms program 'cos otherwise program might just stop.
            // http://***.com/questions/1583351/silent-failures-in-c-seemingly-unhandled-exceptions-that-does-not-crash-the-pr

            try
            
                int colindex = dataGridView1.CurrentCell.ColumnIndex;

                Graphics agraphics = this.CreateGraphics();

                SizeF headerTextSize = agraphics.MeasureString(dataGridView1.Columns[colindex].HeaderText, dataGridView1.EditingControl.Font);

                // sometimes it goes black and this link here says to use editing control http://***.com/questions/3207777/datagridview-cell-turns-black-when-accessing-editedformattedvalue

                // string stredit=dataGridView1.CurrentCell.EditedFormattedValue.ToString();
                string stredit=myDataGridView.EditingControl.Text;
                SizeF curCellTextSize = agraphics.MeasureString(stredit, dataGridView1.EditingControl.Font);
                //SizeF curCellTextSize = agraphics.MeasureString(dataGridView1.CurrentCell.GetEditedFormattedValue.ToString(), dataGridView1.EditingControl.Font);
                int curCellTextSize_i = (int)Math.Round(curCellTextSize.Width, 0);

                int headerCellSize = dataGridView1.Columns[colindex].Width;

                textBox2.Text = headerTextSize.Width.ToString();
                textBox3.Text = headerCellSize.ToString();

                // find biggest existing one
                int maxcelltextincol = (int)Math.Round(headerTextSize.Width,0);
                // the max size, at least for the header, includes a bit of padding.. 
                maxcelltextincol += 20;
                int tempcelllength=0;
                for(int i=0; i<dataGridView1.Rows.Count;i++) 
                    if (dataGridView1.Rows[i].Cells[colindex].Value == null) dataGridView1.Rows[i].Cells[colindex].Value = "";

                    tempcelllength = (int)Math.Round(agraphics.MeasureString(dataGridView1.Rows[i].Cells[colindex].Value.ToString(), dataGridView1.EditingControl.Font).Width, 0);

                    if (tempcelllength > maxcelltextincol) maxcelltextincol = tempcelllength;       
                


            //    textBox2.Text = "PRE curCellTextSize_i=" + curCellTextSize_i + " " + "dgvw=" + dataGridView1.Columns[colindex].Width.ToString() + " max=" + maxcelltextincol.ToString() +  " prevstringlength=";

                string txtinwhatiamediting = stredit;

                SizeF sizelengthoftxtinwhatiamediting = agraphics.MeasureString(txtinwhatiamediting, dataGridView1.Font); //intermediate
                int lengthoftxtinwhatiamediting=(int)Math.Round(sizelengthoftxtinwhatiamediting.Width,0);

                //if(lengthoftxtinwhatiamediting>maxcelltextincol) 
                int amountovermax = lengthoftxtinwhatiamediting - maxcelltextincol;    


                int oldcolwidth = dataGridView1.Columns[colindex].Width;
                if (amountovermax < 0)  dataGridView1.Columns[colindex].Width = maxcelltextincol; return; 


                dataGridView1.Columns[colindex].Width = maxcelltextincol + amountovermax;
                int newcolwidth = dataGridView1.Columns[colindex].Width;
                   //dataGridView1.Width += (int)Math.Round((double)amountovermax,0);
                dataGridView1.Width += newcolwidth - oldcolwidth;
                this.Width += newcolwidth - oldcolwidth;
                //   textBox2.Text = "curCellTextSize_i=" + curCellTextSize_i + " " + "dgvw=" + dataGridView1.Columns[colindex].Width.ToString() + " max=" + maxcellincol.ToString();

                if (curCellTextSize_i > maxcelltextincol) maxcelltextincol = curCellTextSize_i;

                  // textBox5.Text= "POST curCellTextSize_i=" + curCellTextSize_i + " " + "dgvw=" + dataGridView1.Columns[colindex].Width.ToString() + " max=" + maxcelltextincol.ToString() + "prevstring=" + prevString + " prevstringlength=" + prevtextsize + " diff=" + diff;
                 //  textBox5.Text = "POST curCellTextSize_i=" + curCellTextSize_i + " " + "dgvw=" + dataGridView1.Columns[colindex].Width.ToString() + " max=" + maxcelltextincol.ToString() + " diff=" + amountovermax;


            
            catch (Exception ee)  MessageBox.Show(ee.ToString());                                 
        

        private void Form1_Load(object sender, EventArgs e)
        
            try
            
                //dataGridView1.AllowUserToAddRows = false;
                dataGridView1.Font = new System.Drawing.Font("David", 30.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                dataGridView1.Rows.Add(1);

                dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
                dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;                

                Graphics g = this.CreateGraphics(); // should be in a using.

                Font fontA = new System.Drawing.Font("David", 30.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

                SizeF headerSize = g.MeasureString(dataGridView1.Columns[0].HeaderText, fontA);

                int totalcolwidth = dataGridView1.RowHeadersWidth + 40; // about 40+70
                //MessageBox.Show(totalcolwidth.ToString());
                for (int i = 0; i < dataGridView1.Columns.Count; i++)
                    totalcolwidth += dataGridView1.Columns[i].Width;

              //  MessageBox.Show(totalcolwidth.ToString());
              //  MessageBox.Show(dataGridView1.Width.ToString());
                int diff = totalcolwidth - dataGridView1.Width;
                dataGridView1.Width = totalcolwidth;
              //  MessageBox.Show(dataGridView1.Width.ToString());
                this.Width += diff;

            
            catch (Exception exc)
            
                MessageBox.Show("exception ");
                MessageBox.Show(exc.ToString());
            
        


    

【讨论】:

【参考方案7】:

这个解决方案(我的最新)使用与使用 2 个 datagridviews 的答案类似的技术,但它只使用一个 datagridview 来管理它。

当在单元格中输入文本时,它会创建一个新行,并将该文本输入到该行中相应列的该行中。然后它会看到新的宽度应该是多少,并将列扩展到该宽度并删除该行。

这是对我所拥有的东西的编辑,它改进了它。因为事实证明我可以注释掉 cellbeginedit 和 cellendedit 方法。并且还发现,上一个虽然没问题,但是稍微修改一下就会出现黑格的bug,这里说一下。只要我自动调整所有列的大小,我就会避免使用黑色单元格。 (我使用 EditingControl.Text)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace dgveditresize

    public partial class Form1 : Form
    

        public Form1()
        
            InitializeComponent();
        

        private void Form1_Load(object sender, EventArgs e)
        

            //DGVprocs.dgv = dataGridView1;
            dataGridView1.AllowUserToAddRows = false;

            autoshrinkwholedgv();

            //DGVprocs.autoshrink_off_wholedgv__preservewidths(); not necessary
            dataGridView1.Rows.Add(5);
            //dataGridView1.CellBeginEdit += OnCellBeginEditExpandCol;

             dataGridView1.EditingControlShowing += DataGridView1_EditingControlShowing;

          //  MessageBox.Show(dataGridView1.Columns[1].Width.ToString());
        


        private void DataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        

           // MessageBox.Show(dataGridView1.Columns[1].Width.ToString());



            // http://***.com/questions/37505883/how-can-i-dynamically-detect-the-characters-in-a-datagridview-cell-execute-co

            //if(DGVprocs.isshrinkon()==false)  MessageBox.Show("err ")

            if (e.Control is TextBox)
            
                var tbox = (e.Control as TextBox);

                // De-register the event FIRST so as to avoid multiple assignments (necessary to do this or the event
                // will be called +1 more time each time it's called).

                tbox.TextChanged -= A_Cell_TextChanged;
                tbox.TextChanged += A_Cell_TextChanged;
            



        

        private void A_Cell_TextChanged(object sender, EventArgs e)
        

            dataGridView1.Rows.Add(1);

            //MessageBox.Show(dataGridView1.Rows.Count+" rows");

            int colindex = dataGridView1.CurrentCell.ColumnIndex;


            int oldcolwidth = dataGridView1.CurrentCell.Size.Width;
            //string stredit=dataGridView1.CurrentCell.EditedFormattedValue.ToString();
            string stredit = dataGridView1.EditingControl.Text;

            //dgvtest.Rows[0].Cells[0].Value = stredit;
            dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[dataGridView1.CurrentCell.ColumnIndex].Value = stredit;
            //MessageBox.Show(dataGridView1.Rows.Count + " rows");
            //int newcolwidth = dgvtest.Rows[0].Cells[0].Size.Width;

            //autoshrinkcurrentcol(); // WORSE   (1)  WW
            autoshrinkwholedgv(); //added BETTER (2)  XX
            int newcolwidth = dataGridView1.Rows[dataGridView1.Rows.Count - 1].Cells[dataGridView1.CurrentCell.ColumnIndex].Size.Width;
            autoshrinkoff_wholedgv_preservewidths(); //added BETTER (3) YY
           // autoshrink_off_currentcol_preservewidth(); // WORSE (4)  ZZ
             /*               
             WAS ERROR WITH THIS ONE..
             IF YOU TYPE IN THE FIRST CELL THEN HIT DOWN ARROW TWICE
             THEN TYPE THEN IT GOES BLACK
             BUT PROBLEM RESOLVED  SINCE USING 2,3 RATHER THAN 1,4                    
              */
            // doing either  1,4  or 2,3
            // no comparison
            // 1,4 causes blackness.
            // 2,3 and it works
            // all of them is just same as 2,3 not surprising.
            // but funny that 1,4 causes blackness.


            //MessageBox.Show("removing row");

            if(dataGridView1.AllowUserToAddRows)  MessageBox.Show("programmer msg- issue in 'cell's textchanged method', allowusertoaddrows must be false otherwise an exception is thrown by the next line dataGridView1.Rows.RemoveAt(dataGridView1.Rows.Count - 1);"); Application.Exit(); 
                // requires user not add row set to true.
                dataGridView1.Rows.RemoveAt(dataGridView1.Rows.Count - 1);

            //MessageBox.Show(dataGridView1.Rows.Count + " rows");

            int headercellsize = dataGridView1.Columns[colindex].HeaderCell.Size.Width;

            // find biggest existing one
            int maxcellincol = headercellsize;

            int tempcelllength = 0;
            for (int i = 0; i < dataGridView1.Rows.Count; i++)
            
                if (dataGridView1.Rows[i].Cells[colindex].Value == null) dataGridView1.Rows[i].Cells[colindex].Value = "";

                //length of all others but not current.
                tempcelllength = dataGridView1.Rows[i].Cells[colindex].Size.Width;

                if (tempcelllength > maxcellincol) maxcellincol = tempcelllength;
            



            int diffcol = newcolwidth - oldcolwidth;

            // new isn't an ideal name.. 'cos it's not made new yet.. and 'cos if it's smaller than the max one then we won't make it the new one.. but it will be the new one if it's bigger than the max.

             txtdesc.Text = "";
            txtdesc.Text += "newcol\r\n";
            txtdesc.Text += "maxcellincol=" + maxcellincol + "\r\n";


            //if (newcolwidth < maxcellincol)  != even if = then fine.

            // say we move that earlier
            //dataGridView1.Rows.RemoveAt(dataGridView1.Rows.Count - 1);

            //DGVprocs.autoshrinkoff_preservecurrentcolwidth();


            //if (dataGridView1.Columns[colindex].Width == newcolwidth)
            if (oldcolwidth == newcolwidth)
            txtwidthcomp.Text="old width is equal to cur width diff="+diffcol;
            else
                txtwidthcomp.Text="old width is not equal to cur width diff="+diffcol;

            //shrink should never be on while there's an editbox showing.
            //if (diffcol>0) if (DGVprocs.isshrinkon() == true) MessageBox.Show("shrink is on this may be why it's not resizing");
            // when turning autoshrink off a)it should be done after the editbox it will freeze the editbox to the size that it was. b)when it is done it should be done in a preservational way. getting all col sizes beforehand and turning shrink off and setting all cols to that size that they were 
            // DGVprocs.autoshrinkoff();
            // shrink has to be off for the current column.. doesn't matter about the rest of it.
            // if(diffcol>0) if(DGVprocs.isshrinkoncurrentcol()==true) MessageBox.Show("shrink is on(cur col) this may be why it's not resizing");



            dataGridView1.Columns[colindex].Width = newcolwidth;
            dataGridView1.Width += diffcol;


            // i think autoshrink while the editbox is showing is wrong.
            // you need to autoshrink it to size of editbox.
//            DGVprocs.autoshrink();


        


        public void autoshrinkwholedgv()
        

            dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
            dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;

            return;
        

        public void autoshrinkcurrentcol()
        

            dataGridView1.Columns[getcurrentcol()].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;

            //this may be optional.
            dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;

            // DGVprocs.dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;

            return;
        

        public int getcurrentcol()
        
            if (dataGridView1.CurrentCell == null)  MessageBox.Show("Programmer msg - getcurrentcol() error, current cell not selected"); Application.Exit(); 
            if (dataGridView1.CurrentCell.Value == null) dataGridView1.CurrentCell.Value = "";

            return dataGridView1.CurrentCell.ColumnIndex;
        

        public void autoshrink_off_currentcol_preservewidth()
        
            int w =  dataGridView1.Columns[getcurrentcol()].Width;
            dataGridView1.Columns[getcurrentcol()].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
            dataGridView1.Columns[getcurrentcol()].Width = w;
        

        public void autoshrinkoff_wholedgv_preservewidths()
        
            // deal with the 73,100 bug.. whereby if you ave autoresize on immediately, then a DGV with Column1 Colum2, Column3 e.t.c. has width of 73. But then when turning autoresize off it goes to 100. 

            int[] colsizes = new int[dataGridView1.Columns.Count];

            for (int i = 0; i < dataGridView1.Columns.Count; i++)
                colsizes[i] = dataGridView1.Columns[i].Width;

            dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
            dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;

            for (int i = 0; i < dataGridView1.Columns.Count; i++)
                dataGridView1.Columns[i].Width = colsizes[i];


            return;
        

    



【讨论】:

上面似乎没有得到黑色单元格的问题,尽管稍微修改代码以使用行 WW 和 ZZ 会导致它。这看起来像 datagridview 的一个错误,在这里提到了 connect.microsoft.com/VisualStudio/feedback/details/2878864/… 和一个类似的错误在这里提到了 ***.com/questions/3207777/…

以上是关于DataGridView:编辑时更改编辑控件大小的主要内容,如果未能解决你的问题,请参考以下文章

c#中datagridview中datasource反复赋值没有变化?

DataGridView如何通过按下escape来检测用户何时从编辑控件中出来?

DataGridView编辑后立即更新到数据库的两种方法

winform文本编辑器:htmleditor,获取它的子控件

Datagridview组合框未在单击/编辑时选择

C# 在 DataGridView 上显示我的自定义控件,即使不编辑