Sliding the Panel - c#

I'm using WinForms. In My form i have a button and a panel. When i click on that button i want to slide the panel to the right. I'm having issues with the code. Currently I'm getting red error lines under
= panel2.Location.X + 1;
Error Message: Cannot implicitly convert type int to System.Drawing.Point
I was trying to move the panel with the similar approach i did by growing the panel. I provided that in my code. How can i move the panel?
private void btn_Right_Click(object sender, EventArgs e)
{
// Make Panel Grow
//while (panel1.Width < 690)
//{
// panel1.Width = panel1.Width + 1;
//}
while (panel2.Location.X < 690)
{
panel2.Location = panel2.Location.X + 1;
}
}

You get an error because you try to set the location with an integer. You will need a new point instance:
panel2.Location = new Point(panel2.Location.X, panel2.Location.Y + 1);

Try using .Left instead of .Location.X
This works in VB...
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
If sender.text = ">" Then
Do Until Panel1.Left > Me.Width - 50
Panel1.Left += 1
Loop
sender.text = "<"
Else
Panel1.Left = 511
sender.text = ">"
End If
End Sub
I'm surprised it is a smooth as it is - panel is empty however.

Related

Auto positioning controls (without TableLayoutPanel)

My problem is in the picture:
How can i position automatically the next control (textbox in this sample), without a TableLayoutPanel?
Do you mean you want the TextBox move left/right based on the width of Label?
private void button2_Click(object sender, EventArgs e) {
int gap1 = textBox1.Left - label1.Right;
label1.AutoSize = true;
label1.Text = "long long long long long long long long";
textBox1.Left = label1.Right + gap1;
int gap2 = textBox1.Left - label1.Right;
label2.AutoSize = true;
label2.Text = "s";
textBox2.Left = label2.Right + gap2;
}
You firstly record the gap between the TextBox and Label, then set the AutoSize to true, followed by setting the new content of Label, finally you can move the TextBox accordingly.
Before:
After:
If you need to align multiple TextBox, or the width of TextBox as well, it would be more complicated, but you can follow the similar logic.
However, you have to write your own code but not doable in the Design view, as the Anchor of control is to the parent container but not the sibling control. Well, in Xcode on Mac you could do this, but AFAIK Visual Studio does not have this feature out of the box.
Here's a simple example of using a counter to track the number of controls created and compute the proper Y position:
private int counter = 0;
private void button1_Click(object sender, EventArgs e)
{
counter++;
int y = counter * 25;
Label lbl = new Label();
lbl.Text = "Label " + counter.ToString();
lbl.Location = new Point(5, y);
TextBox tb = new TextBox();
tb.Location = new Point(lbl.Bounds.Right + 5, y);
this.Controls.Add(lbl);
this.Controls.Add(tb);
}

How to make my panel move?

What's the deal, i have an imagePanel (u can look at it as a picturePanel)
called imagePanel1 (i imported it so i don't have to make scroll Bars :))
and i have a treeView on the left side, from witch i can drag a node, and drop it over the imagePanel, where i get a Location of the drop, and on that location i create a normal panel called panel1
And so i do 100 times, so at the end i ll have an imagePanel full of small panels...
Now is the problem, when i click on the imagePanel (where a panel is located)
I want that panel to be selected on MousePress, and moved on mouseMove, and eventualLy deleted on a btnDelete...
Here is the code for the imagePanel:
//***********************************************************************
private void imagePanel1_DragDrop_1(object sender, DragEventArgs e)
{
Type testTip = new TreeNode().GetType();
YLScsImage.ImagePanel dropPicturePanel = (YLScsImage.ImagePanel)sender;
TreeNode movedNode;
_mouseDownSelectedWindow = Rectangle.Empty;
if (e.Data.GetDataPresent(testtype))
{
movedNode= (TreeNode)e.Data.GetData(testType);
dropPicturePanel.Tag = movedNode.Tag;
movedNode.ImageIndex = 1;
movedNode.SelectedImageIndex = 1;
movedNode.ForeColor = Color.Gray;
//**************************************
//HERE IS THE CODE FOR THE CREATED PANEL
Panel panel1 = new Panel();
Point point1 = this.PointToClient(new Point(e.X - 278, e.Y - 19)); //the imagePanel1 is on the form at the point 278,19
panel1.AllowDrop = true;
panel1.Location = point1;
panel1.BackgroundImage = iltest.Images[0]; //nvm
panel1.Height = 16;
panel1.Width = 16;
imagePanel1.Controls.Add(panel1); //am adding it to the imagePanel1
//saving the locations of each panel
string path = #"C:\Users\Cosic\Desktop\ICR\TABELA3_Paneli.txt"; // path to file
if (!File.Exists(path))
File.Create(path);
if (panelBr == 0)
System.IO.File.WriteAllBytes(path, new byte[0]); //brise ceo text iz fajla
TextWriter sw = new StreamWriter(path, true);
sw.WriteLine(e.X + "; " + e.Y + "; " + panel1.Width + "; " + panel1.Height + ";");
sw.Close();
//am done with saving
panelBr++;//nvm
}
}
tell me if u need some more code...i got a lot of it ;)
and sorry for bad english, am not that good as I would like to be...
I solved the problem, like this:
panel1.MouseUp += new MouseEventHandler(panel1_MouseUp);
just write panel1.anyEventUWant += and 2 times tab button....
it generate automaticly a new function with a single code line in it
here is an example
void panel1_MouseUp (object sender, EventArgs e)
{
//throw new NotImplementedException();
}
U can access the panel like this: ((object)sender).

KryptonSeparator resizing issue

Scenario
I'm in need of help using a KryptonSeparator.
I would like to use the separator in the image below to resize the width of the left and right controls:
Problem
The problem is when I try to move the separator to the left then it creates a very disturbing visual effect, and more or less the same thing happens when I move the separator to the right, but to the left is much more appreciable (and horrible):
I think that I'm not using properly the eventargs of the KryptonSeparator because when I move the separator to the left I'm basing the calculations using the separator's width instead the event data (because I don't know how to do it properly).
Question
What modifications I should do in my code to fix the resizing problem?
Code
Both the left and the right control has a MinimumSize property assigned, I'm trying to stop the resize if MinimumSize.Width is reached.
This is the source code, in VB.Net:
''' <summary>
''' Handles the SplitterMoving event of the KryptonSeparator1 control.
''' </summary>
Private Sub KryptonSeparator1_SplitterMoving(ByVal sender As Object, ByVal e As SplitterCancelEventArgs) _
Handles KryptonSeparator1.SplitterMoving
Dim separator As KryptonSeparator = DirectCast(sender, KryptonSeparator)
Dim leftCtrl As Control = Control1
Dim rightCtrl As Control = Control2
If (e.MouseCursorX > 0) _
AndAlso Not ((rightCtrl.Size.Width - e.MouseCursorX) < rightCtrl.MinimumSize.Width) Then
separator.Location = New Point(separator.Location.X + e.MouseCursorX, separator.Location.Y)
leftCtrl.Width += e.MouseCursorX
rightCtrl.Width -= e.MouseCursorX
rightCtrl.Left = separator.Right
ElseIf (e.MouseCursorX < 0) _
AndAlso Not ((leftCtrl.Size.Width + e.MouseCursorX - separator.Width) < leftCtrl.MinimumSize.Width) Then
separator.Location = New Point(separator.Location.X - separator.Width, separator.Location.Y)
leftCtrl.Width -= separator.Width
rightCtrl.Width += separator.Width
rightCtrl.Left = separator.Right
End If
End Sub
This is the source code, in C#:
/// Handles the SplitterMoving event of the KryptonSeparator1 control.
/// </summary>
private void KryptonSeparator1_SplitterMoving(object sender, SplitterCancelEventArgs e)
{
KryptonSeparator separator = (KryptonSeparator)sender;
FolderView leftCtrl = this.FolderView_Files;
KryptonListBox rightCtrl = this.KryptonListBox_Files;
if ((e.MouseCursorX > 0) && !((rightCtrl.Size.Width - e.MouseCursorX) < rightCtrl.MinimumSize.Width)) {
separator.Location = new Point(separator.Location.X + e.MouseCursorX, separator.Location.Y);
leftCtrl.Width += e.MouseCursorX;
rightCtrl.Width -= e.MouseCursorX;
rightCtrl.Left = separator.Right;
} else if ((e.MouseCursorX < 0) && !((leftCtrl.Size.Width + e.MouseCursorX - separator.Width) < leftCtrl.MinimumSize.Width)) {
separator.Location = new Point(separator.Location.X - separator.Width, separator.Location.Y);
leftCtrl.Width -= separator.Width;
rightCtrl.Width += separator.Width;
rightCtrl.Left = separator.Right;
}
}
//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================
UPDATE
I've updated the codes above to simplify the reading, and I'm sharing this new video where you can see the design problem:
www.youtube.com/watch?v=-MhmyE3MZX0
First, you need to get where the user clicked before the dragging,mouse down event of splitter control and total width of three controls:
Private mouse_Down As Point //you can use an integer also because y coordinate remains the same
Private totalWidth As Integer
//mouse down event
mouse_Down.X = e.MouseCursorX
totalWidth = seperator.Width + LeftControl.Width + RightControl.Width
Private Sub KryptonSeparator1_SplitterMoving(ByVal sender As Object, ByVal e As SplitterCancelEventArgs) Handles KryptonSeparator1.SplitterMoving
Dim separator As KryptonSeparator = DirectCast(sender, KryptonSeparator)
Dim leftCtrl As Control = Control1
Dim rightCtrl As Control = Control2
Dim leftWidth, rightWidth As Integer
leftWidth = leftCtrl.Width + (e.MouseCursorX - mouse_Down.X)
rightWidth = rightCtrl.Width - (e.MouseCursorX - mouse_Down.X)
If leftWidth <= leftCtrl.MinimumSize.Width Then
leftCtrl.Width = leftCtrl.MinimumSize.Width
separator.Left = leftCtrl.Left + leftCtrl.MinimumSize.Width
rightCtrl.Left = leftCtrl.Left + leftCtrl.MinimumSize.Width + separator.Width
rightCtrl.Width = totalWidth - leftCtrl.MinimumSize.Width - separator.Width
Return
End If
If rightWidth <= rightCtrl.MinimumSize.Width Then
leftCtrl.Width = totalWidth - rightCtrl.MinimumSize.Width - separator.Width
separator.Left = leftCtrl.Left + leftCtrl.Width
rightCtrl.Left = leftCtrl.Left + leftCtrl.Width + separator.Width
rightCtrl.Width = rightCtrl.MinimumSize.Width
Return
End If
separator.Left += (e.MouseCursorX - mouse_Down.X)
leftCtrl.Width = leftWidth
rightCtrl.Width = rightWidth
rightCtrl.Left = leftCtrl.Left + leftWidth + separator.Width
End Sub
EDIT
Try this:
//mouse down event
//mouse_Down.X = e.MouseCursorX
mouse_Down.X = MousePosition.X
mouse_Down.Y = MousePosition.Y
mouse_Down = seperator.PointToClient(mouse_Down)
totalWidth = seperator.Width + LeftControl.Width + RightControl.Width
and in SplitterMoving:
Dim leftWidth, rightWidth As Integer
Dim pnt As Point
pnt.X = MousePosition.X
pnt.Y = MousePosition.Y
pnt = seperator.PointToClient(pnt)
//replace e.MouseCursorX with pnt.X
...
EDIT 2
Your logic of resizing the two windows have two minor bugs:
Using e.MouseCursorX to determine the direction of the resizing(left or right) is wrong, eg you move the cursor to the left(left direction),
remaining inside the separator, e.MouseCursorX is still positive, so you are resizing to the right(until of course e.MouseCursorX becomes negative)
instead of left !
Your code checks for the minimum size but does nothing when the comparison is false, meaning when the resulting size of the control is smaller.
When that happens you need to actually set the size of the control eg lets say the minimum size is 50 and the controls size is 55. If the resize is very fast, the resulting size of the control may become 49. Your code does nothing(comparison is false) and the size of
the control remains 55 instead of seting it to 50.
My solution solves both of these situations. However, the real issue of your horible effect as you said is not these two bugs. It is actually,
the way too slow responsiveness of the application, when you resize the controls. To be more specific, when you resize and move the right
control(ListBox_Files). You can check it your self if you drag and drop a small number(1 or 2) of files and see the result. It is a tremendous
difference. That unfortunately tells me that you can not do anything about it. You need to change the logic of the resize. Two solutions:
Use one control and custom draw everything, text, icons, vertical-horizontal scrollbars etc.. (not recommended!)
Do what visual studio and other application is doing. Do not resize the controls until you release the button. Just show a vertical line:

Make a Picturebox Appear on Mouse Location When Moused is Clicked in C#

I have made a program that measures distances from two user placed pictureboxes. At the moment it all works fine except, where i want the dots to go the pictureboxes do not go into that location where i clicked. This is my current code in Mouseclick event of the picturebox the two dots (pictureboxes) are to be placed and measure in:
if (Dotter == 1)
{
dot1.Visible = true;
dot1.Location = e.Location;
Dotter = 2;
}
else if (Dotter == 2)
{
dot2.Visible = true;
dot2.Location = e.Location;
Dotter = 1;
}
This is the actual placing function for the two pictureboxes at the moment, please help.
Thanks
Extra Info:
It is in the picturebox where the image which can be measured using these two dots, and is in its mouseclick event, and its on a Windows Form. Also when i click they are placed but are miles away from where i clicked, and sometimes even appear outside the picturebox when they shouldn't be.
Thanks for your help this is what i have done to make it work. I have changed the e.Location part of my code to this:
if (Dotter == 1)
{
dot1.Visible = true;
dot1.Left = e.Location.X + capturebox.Left - 10;
dot1.Top = e.Location.Y + capturebox.Top - 10;
Dotter = 2;
}
else if (Dotter == 2)
{
dot2.Visible = true;
dot2.Left = e.Location.X + capturebox.Left - 10;
dot2.Top = e.Location.Y + capturebox.Top - 10;
Dotter = 1;
}
So basically changing the dot's locations to Left and Top and then getting the mouse click location for x and y and then made the point at which the dot will appear to be in the middle of it by minusing 10 from each.

DataGridView: Change Edit Control size while editing

in the DataGridView I want the cell size to expand according to the string length when I edit the cell. Excel does the same.
In the DataGridView, when entering edit mode, a DataGridViewTextBoxEditingControl is 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.
Any ideas on how to get this working?
Thanks,
Timo
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.
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:
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();
}
}
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)
NOTE: The following code assumes that 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:
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;
}
}
This was work for me:
Enable KeyPreview Property of the form and change the body of KeyPress Event of the form to this:
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 ;
I mentioned in my other answer that I had two solutions, this one is the MeasureString solution (as opposed to the second datagridview solution)
any mention of textbox1-5.text e.t.c. has been commented it was just for debugging.
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.
I should probably have used the 'uses' keyword for creating the graphics object, but anyhow.
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());
}
}
}
}
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.
This is the one that uses a second datagridview
Draw a datagridview on a form i've given mine two columns no data.
The code will create a second datagridview also with two columns no data.
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.
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.
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.)
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.
This solution(my latest) uses a similar technique to the answer that uses 2 datagridviews, but it manages it with just one 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)
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;
}
}
}
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.
Let me know.
Thanks

Categories