Windows Develop Bookmark and Share   
 index > Windows Forms Designer > Multiple controls in a single DataGridView cell
 

Multiple controls in a single DataGridView cell

Hi, I need to put a text box and button within a single DataGridView cell, the user should be able to edit the text or click the button which brings out another dialog. But I am not going to use PropertyGrid, use DataGridView only,

____________

text | button |

this is a single cell, user can click the text to modify it, or click the button

I've tried to modify the calender picker example in microsoft.com, but somehow didn't work out, the user cannot edit the text...

Thanks!

Nathan4  Thursday, March 29, 2007 10:17 AM
I have another way to do this, we can take the following steps:

1). Make a usercontrol to host a textbox and a button, as shown in my following sample, the TextAndButtonControl class which inherited from usercontrol.

2). Create a TextAndButtonControl instance(NOTICE: we just need one), add it into the control collection of the DataGridView, initially make it invisible.

3). Handle the DataGridView.CellPainting event to draw a textbox and button style on the cell, which make the cell looked like some kind hosting a usercontrol in it.

4). Handle the DataGridView.CellBeginEdit event to show the usercontrol right in the cell while editing, you can edit in the textbox in the usercontrol and click the button, write your logic in the Click event of the button, I just show a message box for example in this sample.

5). Handle the DataGridView.CellEndEdit event to update the cell value.

6). Handle the DataGridView.Scroll event to reset the location and size of the usercontrol while scrolling. Without handling this, the usercontrol would stay still while scrolling.

That's all. I write a sample for your information. Enjoy taking it.

Any question about this please no hesitate to let me know.

Best Regards.
Zhixin Ye


Code Snippet

System;

System.Collections.Generic;

System.ComponentModel;

System.Data;

System.Drawing;

System.Text;

System.Windows.Forms;

Sample5

public partial class DgvTextAndButton : Form

public DgvTextAndButton()

private void DgvTextAndButton_Load(object sender, EventArgs e)

DataTable dt = new DataTable();

"col1");

"col2");

for (int j = 0; j < 20; j++)

"col1"+j.ToString(),"col2"+j.ToString());

this.dataGridView1.DataSource = dt;

this.dataGridView1.Columns[0].Width = 150;

this.txbtnControl = new TextAndButtonControl();

this.txbtnControl.Visible = false;

this.dataGridView1.Controls.Add(this.txbtnControl);

//Handle this event to paint a textbox and button style in the cell,

//this painting avoid using amount of usercontrols, we just need one

this.dataGridView1.CellPainting += new DataGridViewCellPaintingEventHandler(dataGridView1_CellPainting);

//Handle the cellbeginEdit event to show the usercontrol in the cell while editing

this.dataGridView1.CellBeginEdit += new DataGridViewCellCancelEventHandler(dataGridView1_CellBeginEdit);

//Handle the cellEndEdit event to update the cell value

this.dataGridView1.CellEndEdit += new DataGridViewCellEventHandler(dataGridView1_CellEndEdit);

//Handle the scroll event to reset the location and size of the usercontrol while scrolling

this.dataGridView1.Scroll += new ScrollEventHandler(dataGridView1_Scroll);

TextAndButtonControl txbtnControl;

void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)

if (e.ColumnIndex == 0 && e.RowIndex > -1 && e.RowIndex != this.dataGridView1.NewRowIndex)

Rectangle textRect = e.CellBounds;

Rectangle btnRect = e.CellBounds;

DataGridViewPaintParts.All);

ControlPaint.DrawButton(e.Graphics, btnRect, ButtonState.Normal);

StringFormat formater = new StringFormat();

StringAlignment.Center;

"click", e.CellStyle.Font, new SolidBrush(e.CellStyle.ForeColor), btnRect, formater);

true;

void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)

if (e.ColumnIndex == 0 && e.RowIndex > -1 && e.RowIndex != this.dataGridView1.NewRowIndex)

Rectangle rect = this.dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);

this.txbtnControl.Location = rect.Location;

this.txbtnControl.Size = rect.Size;

this.txbtnControl.Text = this.dataGridView1.CurrentCell.Value.ToString();

this.txbtnControl.ButtonText = "click";

this.txbtnControl.renderControl();

this.txbtnControl.Visible = true;

void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)

if (e.ColumnIndex == 0 && e.RowIndex > -1 && e.RowIndex != this.dataGridView1.NewRowIndex)

this.dataGridView1.CurrentCell.Value = this.txbtnControl.Text;

this.txbtnControl.Visible = false;

void dataGridView1_Scroll(object sender, ScrollEventArgs e)

if (this.txbtnControl.Visible == true)

Rectangle r = this.dataGridView1.GetCellDisplayRectangle(

this.dataGridView1.CurrentCell.ColumnIndex,

this.dataGridView1.CurrentCell.RowIndex,

true);

this.txbtnControl.Location = r.Location;

this.txbtnControl.Size = r.Size;

class TextAndButtonControl : UserControl

private TextBox textbox1;

private Button button1;

public TextAndButtonControl()

this.textbox1 = new TextBox();

this.Controls.Add(this.textbox1);

this.button1 = new Button();

this.Controls.Add(this.button1);

this.renderControl();

this.button1.Click += new EventHandler(button1_Click);

void button1_Click(object sender, EventArgs e)

MessageBox.Show("Click! The value is:" + this.Text);

public string Text

get { return this.textbox1.Text; }

set { this.textbox1.Text = value; }

public string ButtonText

get { return this.button1.Text; }

set { this.button1.Text = value; }

public void renderControl()

this.textbox1.Location = new Point(0, 0);

this.textbox1.Width = 2 * this.Width / 3;

this.textbox1.Height = this.Height;

this.button1.Location = new Point(2 * this.Width / 3, 0);

this.button1.Width = this.Width / 3;

this.button1.Height = this.Height;

nathan:

waht function would you like to fullfill ?

if you can take tow columns,

you can use DatagridviewTextboxColumn and DataGridviewButtonColumn in same row,

and if you want it looks like one column, you can redraw the column head

But I think it more code if you custom your own datagridview cell you want.
Bob zhu - SJTU  Monday, April 02, 2007 3:28 AM
Implementing a DataGridViewCell that hosts a Panel seems like a good option.. Afterwards you can add whatever you like to the panel Wink
timvw  Monday, April 02, 2007 5:49 AM
I have another way to do this, we can take the following steps:

1). Make a usercontrol to host a textbox and a button, as shown in my following sample, the TextAndButtonControl class which inherited from usercontrol.

2). Create a TextAndButtonControl instance(NOTICE: we just need one), add it into the control collection of the DataGridView, initially make it invisible.

3). Handle the DataGridView.CellPainting event to draw a textbox and button style on the cell, which make the cell looked like some kind hosting a usercontrol in it.

4). Handle the DataGridView.CellBeginEdit event to show the usercontrol right in the cell while editing, you can edit in the textbox in the usercontrol and click the button, write your logic in the Click event of the button, I just show a message box for example in this sample.

5). Handle the DataGridView.CellEndEdit event to update the cell value.

6). Handle the DataGridView.Scroll event to reset the location and size of the usercontrol while scrolling. Without handling this, the usercontrol would stay still while scrolling.

That's all. I write a sample for your information. Enjoy taking it.

Any question about this please no hesitate to let me know.

Best Regards.
Zhixin Ye


Code Snippet

System;

System.Collections.Generic;

System.ComponentModel;

System.Data;

System.Drawing;

System.Text;

System.Windows.Forms;

Sample5

public partial class DgvTextAndButton : Form

public DgvTextAndButton()

private void DgvTextAndButton_Load(object sender, EventArgs e)

DataTable dt = new DataTable();

"col1");

"col2");

for (int j = 0; j < 20; j++)

"col1"+j.ToString(),"col2"+j.ToString());

this.dataGridView1.DataSource = dt;

this.dataGridView1.Columns[0].Width = 150;

this.txbtnControl = new TextAndButtonControl();

this.txbtnControl.Visible = false;

this.dataGridView1.Controls.Add(this.txbtnControl);

//Handle this event to paint a textbox and button style in the cell,

//this painting avoid using amount of usercontrols, we just need one

this.dataGridView1.CellPainting += new DataGridViewCellPaintingEventHandler(dataGridView1_CellPainting);

//Handle the cellbeginEdit event to show the usercontrol in the cell while editing

this.dataGridView1.CellBeginEdit += new DataGridViewCellCancelEventHandler(dataGridView1_CellBeginEdit);

//Handle the cellEndEdit event to update the cell value

this.dataGridView1.CellEndEdit += new DataGridViewCellEventHandler(dataGridView1_CellEndEdit);

//Handle the scroll event to reset the location and size of the usercontrol while scrolling

this.dataGridView1.Scroll += new ScrollEventHandler(dataGridView1_Scroll);

TextAndButtonControl txbtnControl;

void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)

if (e.ColumnIndex == 0 && e.RowIndex > -1 && e.RowIndex != this.dataGridView1.NewRowIndex)

Rectangle textRect = e.CellBounds;

Rectangle btnRect = e.CellBounds;

DataGridViewPaintParts.All);

ControlPaint.DrawButton(e.Graphics, btnRect, ButtonState.Normal);

StringFormat formater = new StringFormat();

StringAlignment.Center;

"click", e.CellStyle.Font, new SolidBrush(e.CellStyle.ForeColor), btnRect, formater);

true;

void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)

if (e.ColumnIndex == 0 && e.RowIndex > -1 && e.RowIndex != this.dataGridView1.NewRowIndex)

Rectangle rect = this.dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);

this.txbtnControl.Location = rect.Location;

this.txbtnControl.Size = rect.Size;

this.txbtnControl.Text = this.dataGridView1.CurrentCell.Value.ToString();

this.txbtnControl.ButtonText = "click";

this.txbtnControl.renderControl();

this.txbtnControl.Visible = true;

void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)

if (e.ColumnIndex == 0 && e.RowIndex > -1 && e.RowIndex != this.dataGridView1.NewRowIndex)

this.dataGridView1.CurrentCell.Value = this.txbtnControl.Text;

this.txbtnControl.Visible = false;

void dataGridView1_Scroll(object sender, ScrollEventArgs e)

if (this.txbtnControl.Visible == true)

Rectangle r = this.dataGridView1.GetCellDisplayRectangle(

this.dataGridView1.CurrentCell.ColumnIndex,

this.dataGridView1.CurrentCell.RowIndex,

true);

this.txbtnControl.Location = r.Location;

this.txbtnControl.Size = r.Size;

class TextAndButtonControl : UserControl

private TextBox textbox1;

private Button button1;

public TextAndButtonControl()

this.textbox1 = new TextBox();

this.Controls.Add(this.textbox1);

this.button1 = new Button();

this.Controls.Add(this.button1);

this.renderControl();

this.button1.Click += new EventHandler(button1_Click);

void button1_Click(object sender, EventArgs e)

MessageBox.Show("Click! The value is:" + this.Text);

public string Text

get { return this.textbox1.Text; }

set { this.textbox1.Text = value; }

public string ButtonText

get { return this.button1.Text; }

set { this.button1.Text = value; }

public void renderControl()

this.textbox1.Location = new Point(0, 0);

this.textbox1.Width = 2 * this.Width / 3;

this.textbox1.Height = this.Height;

this.button1.Location = new Point(2 * this.Width / 3, 0);

this.button1.Width = this.Width / 3;

this.button1.Height = this.Height;

Works this code with the keyboard? The first key that the user hit? If the editmode is with the keyboard, the usercontrol don't catch the focus. Why?

pserranop  Sunday, May 20, 2007 11:05 PM
My experience with this approach is the same--under certain circumstances, the custom control gets displayed correctly but the underlying cell still has the focus. So keystrokes go to the underlying cell. Can we prevent the cell from getting focus, or somehow reroute keystrokes to the custom control?

thanks.
sfrenkiel  Tuesday, May 22, 2007 1:48 PM
Hi, I tried this example hoping it would save the day...hehe.
But I am a little confused. When I ran it, the button is shown even though the row is not in focus. Is this correct?

Screenshot

anders_sms  Wednesday, October 17, 2007 7:27 AM

Have you do some extra work on it? I run the code and no that problem.

Zhi-Xin Ye  Wednesday, October 17, 2007 7:42 AM
Didn't do anything else then add a datagridview to the form, thats it.
When you run it, there are no gray buttons in the rows that are not in focus?

Can you make a screenshot?
anders_sms  Wednesday, October 17, 2007 7:51 AM

Contact me with the email in my profile, then I'll send back with a screenshot to you.

Zhi-Xin Ye  Wednesday, October 17, 2007 7:55 AM
Did you get my email?
anders_sms  Wednesday, October 17, 2007 10:30 AM

I've sent it to you twice, haven't you received them?

Zhi-Xin Ye  Wednesday, October 17, 2007 10:31 AM
Ok, now i got it, but it looks like mine. I thought that when not in edit mode the button was hidden. I misunderstood...

But now that i mentioned it, can that be done. Only show the button while in edit mode?
anders_sms  Wednesday, October 17, 2007 10:48 AM

Of course! Just don't handle the CellPainting event. Comment all those code out.

Zhi-Xin Ye  Wednesday, October 17, 2007 11:01 AM
COOL... thank you. Looks and works great.
anders_sms  Wednesday, October 17, 2007 11:08 AM
sfrenkiel wrote:
My experience with this approach is the same--under certain circumstances, the custom control gets displayed correctly but the underlying cell still has the focus. So keystrokes go to the underlying cell. Can we prevent the cell from getting focus, or somehow reroute keystrokes to the custom control?

thanks.


Ofcourse now I encounter this problem, did you ever have a chance to look at it?
anders_sms  Wednesday, October 17, 2007 11:38 AM

sfrenkiel wrote:
My experience with this approach is the same--under certain circumstances, the custom control gets displayed correctly but the underlying cell still has the focus. So keystrokes go to the underlying cell. Can we prevent the cell from getting focus, or somehow reroute keystrokes to the custom control?

thanks.


A trick to fix this problem is like follows:

Handle the EditingControlShowing event to move focus to the TextAndButtonControl.

.......

void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)

{

if (this.dataGridView1.CurrentCell.ColumnIndex == 0)

{

this.BeginInvoke(new MethodInvoker(setfocus));

}

}

private void setfocus()

{

this.txbtnControl.Focus();

}

TextAndButtonControl txbtnControl;

.......

Zhi-Xin Ye  Tuesday, November 25, 2008 11:20 AM
Hai

How to redraw two column to look like a single column in datagridview winforms control


Regards
damodar
damu maddy  Saturday, January 10, 2009 5:31 PM

one problem with this approach is that the first keystroke is still on the underline control. any ideas? anyone?

Lior83  Sunday, June 28, 2009 2:17 AM

Hi timvw

Do you have the sample code?

Jiani  Wednesday, July 08, 2009 4:46 AM

Hello Everyone,

This post has helped me a lot. But I havea problem to ask.

it is, when the column width is changed by the user, i handle the ColumnWidthChanged event like this.

If Me.txbtnControl.Visible = True Then

Dim R As Rectangle = Me.DataGridView1.GetCellDisplayRectangle(Me.DataGridView1.CurrentCell.ColumnIndex, Me.DataGridView1.CurrentCell.RowIndex, True)

Me.txbtnControl.Location = R.Location

Me.txbtnControl.Size = R.Size

Me.DataGridView1.PerformLayout()

End If

The problem is that when i resize the column, when i move the spliter of the column header to resize the column,
the display on txtbtnControl gets scrambled/distorted by the spliter line. Is there a way to rectify that ?
I've been experimenting different things but i cant find a way out..


Thanks in Advance

Regards - Hemant

H C  Wednesday, July 08, 2009 6:38 AM
the above code works great and very useful,

with the help of your code , i show a combobox on cellbeginedit,
when i scroll through the list items in combobox either by using keyboard or mouse , the cell endedit and scroll to the next row.


p.s. i have used combo box as a custom control instead of DatagridviewCombo box column because
i need to set list item of combo box value depending upon one of the field in the record.

in more words , the grid contain a city comboboxcolumn depending upon the city we choose,the items for the postcode combobox (custom control) need to set . everything ok except , we cannot choose the item in the combobox easily by scrolling through the list items.

hope it make sense .

waiting for your advice , is there any better way to accomplish

annamalai
askitanna  Tuesday, July 28, 2009 10:13 AM

You can use google to search for other answers

Custom Search

More Threads

• FlowLayoutPanel.GetPreferredSize() not working as expected in design mode
• Designer error since using VSS
• How to organize a field with "Last changed date/time"?
• Re-evalute CanExtend method?
• Inherited Extender Property Defaults
• Capture OnDragOver
• pushbuttons
• Rectangle on Middle Task bar not indenting when highlighted
• Troubles with collection editor and componentmodel
• panel layout