C# DataGridView:编辑时更改编辑控件大小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/686309/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DataGridView: Change Edit Control size while editing
提问by
in the DataGridViewI want the cell size to expand according to the string length when I edit the cell. Excel does the same.
在DataGridView 中,当我编辑单元格时,我希望单元格大小根据字符串长度进行扩展。Excel 也是如此。
In the DataGridView, when entering edit mode, a DataGridViewTextBoxEditingControlis placed at the cell position. I tried to change the bounds/size of this control, but result is just a short flicker of my desired size. It gets directly overpainted the original, truncated way.
在DataGridView 中,当进入编辑模式时,会在单元格位置放置一个DataGridViewTextBoxEditingControl。我试图改变这个控件的边界/大小,但结果只是我想要的大小的短暂闪烁。它会直接覆盖原始的截断方式。
Any ideas on how to get this working?
关于如何让这个工作的任何想法?
Thanks,
谢谢,
Timo
蒂莫
回答by lb.
Would you like the cell to resize as you type? Or would you like it to resize once the text is entered and enter is hit? The second option is by fair the easiest.
您希望单元格在您键入时调整大小吗?或者您希望它在输入文本并按下 Enter 后调整大小?第二种选择是最简单的。
Let me know.
让我知道。
Thanks
谢谢
回答by Simon Mourier
You need to start by overriding the DataGridViewCell.PositionEditingPanel Method. You need to redefine your own type of column and your own type of cell to access this method.
您需要首先覆盖DataGridViewCell.PositionEditingPanel Method。您需要重新定义自己的列类型和单元格类型才能访问此方法。
Here is an example on how to do it, that multiply the size of the editing panel (the one that owns the editing control) by 2:
这是一个关于如何执行此操作的示例,将编辑面板(拥有编辑控件的面板)的大小乘以 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();
}
}
回答by ARZ
This was work for me:
这对我有用:
Enable KeyPreview
Property of the form and change the body of KeyPress
Event of the form to this:
启用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
}
}
you can limit the pressed keys with e.KeyChar
;
你可以限制按下的键e.KeyChar
;
回答by VineAndBranches
This question is quite old but hopefully my answer helps somebody down the road. I ran across the same problem and was able to use a process similar to the following to make the column width update dynamically as the user typed, in order to ensure the text fit in the column.
这个问题已经很老了,但希望我的回答可以帮助某人。我遇到了同样的问题,并且能够使用类似于以下的过程在用户键入时动态更新列宽,以确保文本适合列。
Events used:
使用的事件:
CellBeginEdit
CellEndEdit
EditingControlShowing
TextBoxKeyPressEvent
(i.e.KeyPress
)
CellBeginEdit
CellEndEdit
EditingControlShowing
TextBoxKeyPressEvent
(即KeyPress
)
NOTE:The following code assumes that AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells
注意:以下代码假设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;
}
}
EDIT:Update to the TextBoxKeyPressEvent
logic to account for Backspace:
编辑:更新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;
}
}
回答by barlop
I have found a few solutions for this
我为此找到了一些解决方案
One uses MeasureString and one datagridview , another creates another datagridview for the purposes of figuring out the correct width of a cell if the cell were to have that content. Another(my latest one) manages it with one datagridview and adding and removing a row.
一个使用 MeasureString 和一个 datagridview ,另一个创建另一个 datagridview 用于确定单元格的正确宽度(如果单元格具有该内容)。另一个(我最新的)用一个 datagridview 管理它并添加和删除一行。
This is the one that uses a second datagridview
这是使用第二个 datagridview 的那个
Draw a datagridview on a form i've given mine two columns no data.
在我给我的两列没有数据的表单上绘制一个 datagridview。
The code will create a second datagridview also with two columns no data.
该代码将创建第二个 datagridview,也有两列没有数据。
Of course the issue that the questioner ran into was that without the editing automatically autosizing, it's not clear what width to set the column. This solution creates another datagridview (call it DGVb), this one not added to the form. And it writes that data to a cell in DGVb, sees what width the cell took, and uses that figure as the figure to set the cell in the proper DGV.
当然,提问者遇到的问题是如果没有编辑自动自动调整大小,不清楚设置列的宽度。此解决方案创建了另一个 datagridview(称为 DGVb),该视图未添加到表单中。并将该数据写入 DGVb 中的单元格,查看单元格的宽度,并使用该数字作为数字将单元格设置在适当的 DGV 中。
Another issue covered by vine, is that with the cell set to autosize, you can't set the column's width programmatically, so you can put code on when the cellbeginedit event is triggered, to set autosize to none, and put it back on when cellendedit is triggered, and another thing is that because setting to none might immediately change the column size a bit e.g. column1 with autosize on might be 73 and then when you turn autosize off it goes to 100, so you can store the size before you put autosize to none, then put autosize to none and set the size to what it was, that way preserving that unwanted size change. That is what is done here, as covered by Vine.
vine 涉及的另一个问题是,当单元格设置为 autosize 时,您无法以编程方式设置列的宽度,因此您可以在触发 cellbeginedit 事件时放置代码,将 autosize 设置为 none,并在触发时将其重新打开cellendedit 被触发,另一件事是因为设置为 none 可能会立即改变列大小,例如启用自动调整大小的 column1 可能是 73,然后当您关闭自动调整大小时它会变为 100,因此您可以在放置之前存储大小autosize 为 none,然后将 autosize 设置为 none 并将大小设置为原来的大小,这样可以保留不需要的大小更改。这就是这里所做的,正如 Vine 所涵盖的那样。
this code expands and shrinks the column and doesn't have weaknesses with backdelete, forward delete or arrow keys, though as of writing, vine's answer has some weaknesses with those keys. I have used TextChanged to avoid those problems. (as opposed to keydown e.t.c.)
这段代码扩展和缩小了列,并且没有使用 backdelete、forward delete 或箭头键的弱点,尽管在撰写本文时,vine 的答案在这些键上有一些弱点。我使用 TextChanged 来避免这些问题。(相对于按键等)
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 += "newcolwidth=" + newcolwidth + "\r\n";
txtdesc.Text += "maxcellincol=" + maxcellincol + "\r\n";
//if (newcolwidth < maxcellincol) != even if = then fine.
dataGridView1.Columns[colindex].Width = newcolwidth;
dataGridView1.Width += diffcol;
}
}
}
The idea of expanding the cell as text is being typed is quite a hack.. but seems visually preferable to this alternative.. which is less tricky to do but doesn't look as nice, that is, to just have the cell expand in size on cellbeginedit, (so set to autosize to none, and set col width to some size like =50), and have it shrink back to size - autosize - on cellendedit) and then i suppose on cellendedit to increase datagridview width so it doesn't get a scroll bar. But then the datagridview col jumps in size and it's not nice to use.
在输入文本时扩展单元格的想法是一个相当大的黑客..但似乎比这个替代方案在视觉上更可取..这样做不那么棘手但看起来不那么好,也就是说,只是让单元格扩展cellbeginedit 上的大小,(因此设置为自动调整为无,并将列宽设置为某种大小,例如 =50),并将其缩小到大小 - 自动调整大小 - 在 cellendedit 上)然后我想在 cellendedit 上增加 datagridview 宽度,因此它不会没有滚动条。但是随后 datagridview col 的大小发生了变化,使用起来并不好。
回答by barlop
I mentioned in my other answer that I had two solutions, this one is the MeasureString solution (as opposed to the second datagridview solution)
我在另一个答案中提到我有两个解决方案,这个是 MeasureString 解决方案(与第二个 datagridview 解决方案相反)
any mention of textbox1-5.text e.t.c. has been commented it was just for debugging.
任何对 textbox1-5.text 等的提及都被评论为仅用于调试。
this, and the other solution, doesn't just resize the column you are editting in, it also resizes datagridview's width, and the form width, though you can easily comment that if you don't want that behaviour.
这个和另一个解决方案不只是调整您正在编辑的列的大小,它还调整了 datagridview 的宽度和表单宽度,但如果您不想要这种行为,您可以轻松评论。
I should probably have used the 'uses' keyword for creating the graphics object, but anyhow.
我可能应该使用 '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://stackoverflow.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://stackoverflow.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());
}
}
}
}
回答by barlop
This solution(my latest) uses a similar technique to the answer that uses 2 datagridviews, but it manages it with just one datagridview.
这个解决方案(我最新的)使用了与使用 2 个 datagridviews 的答案类似的技术,但它只用一个 datagridview 来管理它。
What it does is when text is typed into a cell, it creates a new row, and enters that text into that row at the corresponding column within that row. Then it sees what the new width should be and it expands the column to that width and removes that row.
它的作用是在单元格中输入文本时,它会创建一个新行,然后将该文本输入到该行中相应列的该行中。然后它会看到新的宽度应该是多少,并将列扩展到该宽度并删除该行。
It's an edit of what I had, that improves it.. Since it turned out that I could comment out the cellbeginedit and cellendedit method. And it also found that while the previous one was fine, a slight amendment would cause the bug of a black cell, and that is mentioned here. As long as i'm autosizing all columns I avoid the black cell. (that and using EditingControl.Text as I have)
这是对我所拥有的内容的编辑,从而改进了它.. 事实证明我可以注释掉 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://stackoverflow.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 += "newcolwidth=" + newcolwidth + "\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;
}
}
}