Windows Develop Bookmark and Share   
 index > Windows Forms Designer > DataGridView Custom Cell - Every Cell
 

DataGridView Custom Cell - Every Cell

Hi,
In vb.neti am having trouble adding a listbox to every cell within the datagridview control, I want the listbox user ontrol to be displayed all the time not in edit mode. I have set the grid up using the link below but this code will only let me add the usercontrol to one cell.

http://social.msdn.microsoft.com/forums/en-US/winformsdatacontrols/thread/0060d78a-a51d-4c03-b305-20627b90b598/

Does anyone know if this is even possible to add a listbox/usercontrol to every cell with in the datagridview.

Thanks
Matt
mattvb  Wednesday, May 20, 2009 11:25 AM
Ok, actually the way I'm using in the test project is not efficient when the DataGridView needs to handle lots of data. The efficient way is to show the editing control once the cell got the focus and enter editing mode. After you've done the change, and left the cell, you can draw a ListBox with selectedValue in the cell.

There are several articles showing you the clues on achieving this. Please check out the following articles.

If you have anything hard to understand, please feel free to let me know.

Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Thursday, May 28, 2009 1:06 PM
Hi mattvb,

There's not built-in way to add ListBox to each of the Cell. But there's a workaround. You can create a List of ListBoxes which total number is equal to the Count of the Cells. In the CellPainting event, you can set the location of each ListBox so that you can align the ListBox to each of the cell.

Let me know if you have difficulty in implementing this.

Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Thursday, May 21, 2009 11:23 AM
Hi Bruce.Zhou


Thanks for the quick response just a quick questiion where would i put thelistof listboxs to. As I am going to use a usercontrol colored dotnetlistbox would this be a problem.

Regards
Matt
mattvb  Thursday, May 21, 2009 11:57 AM
Hi mattvb,

Just define a list controls like List<ListBox> lstListBoxes = new List<ListBox>(). Using this method, you may still need to define a dictionary object to hold the state.

Actually, I know another way. That's extending from the DataGridViewCell, then add a ListBox as a class member in the custom DataGridViewCell type. In the OnPaint event, you have the cell location informat, so you can adjust the ListBox to the cell.

Here is a solved thread on how to custom column header cells, you can try to do the same with common cells.


Please feel free to let me know if there's any problem.

Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Thursday, May 21, 2009 12:15 PM
Hi,

Is there no way to add a user control to each cell, I can add one but it will not let me add more than one with the other one staying in place. I have build a dotnet listbox which can drag and drop between each other, like a day planner sort of thing.


Regards
Matt
mattvb  Thursday, May 21, 2009 12:42 PM
Did you mean you want to add two or more UserControls into the cell? I think it can be done, the trick is still the same. Adjust the location of the UserControls so that they look like contained in a cell.

Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Thursday, May 21, 2009 1:01 PM
Sorry about that, what I mean is to have one usercontrol in every cell on the datagridview.

From all the samples does look like it is possible, i have done it before using sourcegrid control devage, using the code below not sure if there is a way to do it in the datagridview.

Dim DataGridListBox As New DotNetListBox

Grid1(y, x) = New SourceGrid3.Cells.Real.CellControl(DataGridListBox)

DataGridListBox = Nothing


Thanks

Regards
Matt

mattvb  Thursday, May 21, 2009 1:32 PM
Yes, that's possible. Please check out the link I've given. You may get some clues.

Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
  • Unmarked As Answer bymattvb Tuesday, May 26, 2009 8:50 PM
  • Marked As Answer bymattvb Thursday, May 21, 2009 4:35 PM
  •  
Bruce.Zhou  Thursday, May 21, 2009 2:27 PM
What iam trying to do Populate a grid with usercontrol listboxs.

Thanks it works now, but i have few problems, intheexample abovefor some reason the ColumnIndex of the first column is always that last column, second column is fine andall other columns just column 0, do you know why this is.

Any idea on how i could make it add the rows correctly not been able to work it out as of yet.

Also when scrolling theusercontrol does not move corectly, it does not move of the screen as it would if it was a text box.

Regards
Matt
mattvb  Wednesday, May 27, 2009 7:55 PM
Hi mattvb,

Would you please provide the code showing how you are doing? The usercontrol does not move correctly, to solve this, it might need to invalidate the DataGridView after a scroll.


Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Thursday, May 28, 2009 8:31 AM

Hi Bruce,

It will not let me attach the whole code i will put it in two messages.

Imports

System

Imports

System.Data

Imports

System.Drawing

Imports

System.Collections

Imports

System.ComponentModel

Imports

System.Windows.Forms

Imports

DataGridCallPlanner.PulsePlanner.xListBox

Namespace

PulsePlanner

Partial Public Class Form1

Inherits Form

Private components As System.ComponentModel.IContainer

Public NUMOFENGINEERS As Integer

Public NUMOFDAYS As Integer

Public dtEngineers As DataTable

Public StartDate As Date

Public EndDate As Date

' ("Provider=SQLNCLI.1;Data Source=XPSERVER\SQLEXPRESS;Persist Security Info=True;Password=198123;User ID=sa;Initial Catalog=PulsePlanner_SQL")

Public ConnectionString As String = ("Data Source=XPSERVER\SQLEXPRESS;Persist Security Info=True;Password=198123;User ID=sa;Initial Catalog=PulsePlanner_SQL")

Public con As SqlClient.SqlConnection

Public Sub New()

InitializeComponent()

AddHandler Me.Load, AddressOf Form1_Load

End Sub

Private headerComboBox As Dictionary(Of [String], ComboBox) = New Dictionary(Of String, ComboBox)()

Friend WithEvents DataGridView1 As System.Windows.Forms.DataGridView

Private Sub InitializeComponent()

Me.DataGridView1 = New System.Windows.Forms.DataGridView

CType(Me.DataGridView1, System.ComponentModel.ISupportInitialize).BeginInit()

Me.SuspendLayout()

'

'DataGridView1

'

Me.DataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize

Me.DataGridView1.Location = New System.Drawing.Point(12, 31)

Me.DataGridView1.Name = "DataGridView1"

Me.DataGridView1.Size = New System.Drawing.Size(718, 298)

Me.DataGridView1.TabIndex = 0

'

'Form1

'

Me.ClientSize = New System.Drawing.Size(885, 362)

Me.Controls.Add(Me.DataGridView1)

Me.Name = "Form1"

CType(Me.DataGridView1, System.ComponentModel.ISupportInitialize).EndInit()

Me.ResumeLayout(False)

End Sub

'start of my code - here goes

Private dt As New DataTable()

Private dtJobs As New DataTable

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Me.DataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing

Me.DataGridView1.ColumnHeadersHeight = 25

'Me.DataGridView1.ColumnHeadersHeight = Me.DataGridView1.ColumnHeadersHeight * 2

Me.DataGridView1.RowCount = 5

' Me.DataGridView1.ColumnCount = 5

Me.DataGridView1.Rows(0).Height = 100

'GetEngineerData()

For x As Integer = 1 To 10 ' NUMOFENGINEERS - 1

Dim col1 As New DataGridColumnListbox()

Me.DataGridView1.Columns.Add(col1)

Next

'For y As Integer = 1 To 3

' Dim row1 As New DataGridColumnListbox()

' Me.DataGridView1.Rows.Add(row1)

'Next

'Me.DataGridView1.Rows.Add(col1)

' AddHandler Me.Paint, AddressOf Form1_Paint

End Sub

Private Sub GetEngineerData()

Dim strSQL As String = ("SELECT * FROM tblEngineers") ' WHERE ""JOBDATE"" BETWEEN '" & FirstDate.ToString("MM/dd/yyyy") & "' AND '") + LastDate.ToString("MM/dd/yyyy") & "' ORDER BY ""JOBDATE"" ASC"

Dim ds As DataSet = ExecuteDataSet(ConnectionString, CommandType.Text, strSQL)

dtEngineers = ds.Tables(0)

NUMOFENGINEERS = (dtEngineers.Rows.Count.ToString())

End Sub

Private Sub UpdateAssignedCalls()

'Dim strSQLUpdate As String

'set xDropTarget Dim c As Control = New xListBox

'Dim ps As Point = Grid1.PointToClient(MousePosition)

'Dim SourceGridPos As SourceGrid3.Position = Grid1.PositionAtPoint(ps)

' xDropTarget = GetXlistbox(SourceGridPos.Row, SourceGridPos.Column)

Dim myConnection As SqlClient.SqlConnection

Dim myCommand As SqlClient.SqlCommand

Dim ra As Integer

myConnection =

New SqlClient.SqlConnection(ConnectionString)

'you need to provide password for sql server

myConnection.Open()

myCommand =

New SqlClient.SqlCommand("Update tblAssignedJobs Set EngineerID='5' where Engineer='Matt'", myConnection)

ra = myCommand.ExecuteNonQuery()

MessageBox.Show(

"Records affected" & ra)

myConnection.Close()

End Sub

'Private Sub btnFillJobs_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFillJobs.Click

' GetJobData()

'End Sub

'SQL Dataset Reader

Public Function ExecuteDataSet(ByVal connectionString As String, ByVal commandType As CommandType, _

ByVal commandText As String) As DataSet

Dim adapter As New SqlClient.SqlDataAdapter(commandText, connectionString)

With adapter.SelectCommand

.CommandType = commandType

End With

Dim data As New DataSet

adapter.Fill(data)

Return data

End Function

End Class

mattvb  Thursday, May 28, 2009 9:01 AM

Public Class TextBoxAndCheckBoxHeaderCell

Inherits DataGridViewColumnHeaderCell

Private Enum SortType

ASC

DesC

None

End Enum

Public uc As New UserControl1

Private sType As SortType

Protected Overloads Overrides Sub OnClick(ByVal e As DataGridViewCellEventArgs)

MyBase.OnClick(e)

If sType = SortType.None Then

sType = SortType.ASC

ElseIf sType = SortType.ASC Then

sType = SortType.DesC

Else

sType = SortType.ASC

End If

End Sub

Public Sub New()

AddHandler uc.MouseClick, AddressOf uc_MouseClick

AddHandler uc.MouseClick, AddressOf uc_ListboxMouseClick

sType = SortType.None

End Sub

Private Sub uc_MouseClick(ByVal sender As Object, ByVal e As MouseEventArgs)

Me.OnClick(New DataGridViewCellEventArgs(Me.ColumnIndex, Me.RowIndex))

MsgBox(

"Clicked " & Me.ColumnIndex & " " & Me.RowIndex)

End Sub

Private Sub uc_ListboxMouseClick(ByVal sender As Object, ByVal e As MouseEventArgs)

Me.OnClick(New DataGridViewCellEventArgs(Me.ColumnIndex, Me.RowIndex))

MsgBox(

"Clicked Istbox " & Me.ColumnIndex & " " & Me.RowIndex)

End Sub

Protected Overloads Overrides Sub Paint(ByVal graphics As Graphics, ByVal clipBounds As Rectangle, _

ByVal cellBounds As Rectangle, ByVal rowIndex As Integer, ByVal dataGridViewElementState As _

DataGridViewElementStates,

ByVal value As Object, ByVal formattedValue As Object, ByVal errorText As String, _

ByVal cellStyle As DataGridViewCellStyle, ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, _

ByVal paintParts As DataGridViewPaintParts)

'MsgBox("RUN")

MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, _

formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)

Me.uc.Location = New Point(cellBounds.Left, cellBounds.Top + 25)

Me.uc.Height = (cellBounds.Height + 50)

Me.uc.Width = cellBounds.Width - 2

End Sub

End Class

Public Class DataGridColumnListbox

Inherits DataGridViewTextBoxColumn

'Inherits DataGridViewTextBoxCell

Private headerCell1 As New TextBoxAndCheckBoxHeaderCell()

Public Sub New()

Me.CellTemplate = New DataGridViewTextBoxCell()

Me.HeaderCell = headerCell1

End Sub

'when the column is just attached to the DataGridView, we add the controls to the dataGridView.

Protected Overloads Overrides Sub OnDataGridViewChanged()

If Me.DataGridView IsNot Nothing Then

Me.DataGridView.Controls.Add(headerCell1.uc)

End If

End Sub

Public ReadOnly Property HeaderCellEx() As TextBoxAndCheckBoxHeaderCell

Get

Return Me.HeaderCell

End Get

End Property

End Class

End

Namespace

mattvb  Thursday, May 28, 2009 9:03 AM

I have removed my custom usercontrol and just put a startand usercontrol with a listbox.

mattvb  Thursday, May 28, 2009 9:04 AM
Hi mattvb,

The thread I suggest to you is to add a custom column header for DataGridView, but not for the general cells. please download this test project , and see if it's the effect is what you want.

Note that, the project is for demonstrating purpose, and is not complete and may contain many errors. I'm posting this test project only want to confirm if it's what you want.


Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Thursday, May 28, 2009 12:40 PM

Yes, this is what i'm trying to do.

Thanks

mattvb  Thursday, May 28, 2009 12:57 PM
Ok, actually the way I'm using in the test project is not efficient when the DataGridView needs to handle lots of data. The efficient way is to show the editing control once the cell got the focus and enter editing mode. After you've done the change, and left the cell, you can draw a ListBox with selectedValue in the cell.

There are several articles showing you the clues on achieving this. Please check out the following articles.

If you have anything hard to understand, please feel free to let me know.

Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Thursday, May 28, 2009 1:06 PM
I am working on rebuilding the test project to perform what i whateda 25 X 25 datagridview full of listbox usercontrol.
Below is the code for scroll event up and down how would i make it work for left and right, tried lots of differents things but cannot get it to work. I have populated the grid with the right amount of listbox's but cannot get the horzontal scroll bar to work correctly.

Private Sub dgv_Scroll(ByVal sender As Object, ByVal e As ScrollEventArgs)'up & down
For i As Integer = 0 To Me.dgv.RowCount - 1
If i >= Me.dgv.FirstDisplayedScrollingRowIndex AndAlso i < Me.dgv.DisplayedRowCount(True) Then
TryCast(Me.dgv.Rows(i).Cells(0), DataGridViewListBoxCell).EditingControl.Visible = True
Else
TryCast(Me.dgv.Rows(i).Cells(0), DataGridViewListBoxCell).EditingControl.Visible = False
End If
Next
End Sub

Thanks in advance.
Matt

mattvb  Friday, May 29, 2009 1:55 PM
Hi mattvb,

As I said before, the test project is used only for demonstrating purpose. If there are many cells in the DataGridView, the application will be very slow using that way. So I hope you can implement one by referring to the above two links.

The code in the scroll event handler is hide the corresponding cell editing controls once those cells are out of view. And the above code just handle the verticall scrolling. In case you are interested in the test project, you can try to do the following changes to handle horizontal scrolling:

void dgv_Scroll(object sender, ScrollEventArgs e)
{
//handle verticall scroll
for (int i = 0; i < this.dgv.RowCount; i++)
{
if (i >= this.dgv.FirstDisplayedScrollingRowIndex && i < this.dgv.DisplayedRowCount(true))
{
(this.dgv.Rows[i].Cells[0] as DataGridViewListBoxCell).EditingControl.Visible = true;
}
else
{
(this.dgv.Rows[i].Cells[0] as DataGridViewListBoxCell).EditingControl.Visible = false;
}
}
//handle horizontal scroll
for (int j = 0; j < this.dgv.ColumnCount; j++)
{
if (j >= this.dgv.FirstDisplayedScrollingColumnIndex && j<dgv.DisplayedColumnCount(true))
{
for(int i=0;i<this.dgv.RowCount;i++)
(this.dgv.Rows[i].Cells[j] as DataGridViewListBoxCell).EditingControl.Visible = true;
}
else
{
for (int i = 0; i < this.dgv.RowCount; i++)
(this.dgv.Rows[i].Cells[j] as DataGridViewListBoxCell).EditingControl.Visible = false;
}
}

}

Best regards,
Bruce Zhou
Please mark the replies as answers if they help and unmark if they don't.
Bruce.Zhou  Saturday, May 30, 2009 1:04 AM

Hi,

I believe this is a similar problem. I am trying to do a super simple DataGridViewRichTextCell. The cellwill not have editing or resizing. However, this will have the ability to cut/copy and click a link (e.g. the basic functions of a RichTextBox). If I create the very simple class below, it works 95% of the way, HOWEVER, after there are a few rows in the table, the paint method keeps getting called. Even after the form has rendered, the paint method is continuously called creating a strange flickering and VERY slow performance. From trial and error, I know that adding the RichTextBox to the DataGridView.Controls is related to the problem.

Do you have any ideas?

Thanks!


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace SecureNote.Display
{
class MinimalRichTextBoxCell : DataGridViewCell
{
private RichTextBox _richTextBox = null;
protected override System.Drawing.Rectangle GetContentBounds(System.Drawing.Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex)
{
//DataGridViewAdvancedBorderStyle style;
//DataGridViewElementStates states;
//Rectangle rectangle;
if (cellStyle == null)
{
throw new ArgumentNullException("cellStyle");
}
if (((base.DataGridView == null) || (rowIndex < 0)) || (base.OwningColumn == null))
{
return Rectangle.Empty;
}
// object obj2 = this.GetValue(rowIndex);
// object formattedValue = this.GetFormattedValue(obj2, rowIndex, ref cellStyle, null, null, DataGridViewDataErrorContexts.Formatting);
return this.DataGridView.GetCellDisplayRectangle(this.ColumnIndex, this.RowIndex, true);
 
// return base.GetContentBounds(graphics, cellStyle, rowIndex);
}
 
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
if (_richTextBox == null || _richTextBox.IsDisposed)
_richTextBox = new RichTextBox();
_richTextBox.Rtf = (string)value;
this.PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
Rectangle internalCellsBounds = cellBounds;
_richTextBox.BackColor = this.Style.BackColor;
_richTextBox.ForeColor = this.Style.ForeColor;
_richTextBox.Location = new Point(cellBounds.Left, cellBounds.Top);
_richTextBox.Size = new Size(cellBounds.Width, cellBounds.Height);
_richTextBox.Refresh();
this.DataGridView.Controls.Add(_richTextBox);
}
}
}

jmauster  Sunday, July 12, 2009 9:31 PM

You can use google to search for other answers

Custom Search

More Threads

• prob while doing project in VS2005 using C#.
• How to Implement an Event Binding Service?
• Textbox Focus issue
• VB Version of Outlook Calendar Look and Feel
• textbox border color
• Site Property
• can't save collection in disgner
• properties window not refreshing
• Contol-Derived Class invoking via DLLImport causes hickups
• display smart tags explicitely