Welcome to Dream.In.Code
Getting C# Help is Easy!

Join 131,708 C# Programmers for FREE! Get instant access to thousands of C# experts, tutorials, code snippets, and more! There are 2,386 people online right now. Registration is fast and FREE... Join Now!




c# datagrid/combobox add-a-row bug

 
Reply to this topicStart new topic

c# datagrid/combobox add-a-row bug, trouble adding rows

snetter
post 17 May, 2005 - 07:24 AM
Post #1


New D.I.C Head

*
Joined: 17 May, 2005
Posts: 5

Hi all,
I've been stuck on this bug for a couple weeks and decided it's time to see if the wide world of forums can help out. Thanks in advance for any help you can give. My situation:

I've created a custom class (with some borrowing from MSDN) DataGridComboBoxColumn that allows a combobox to be placed in a datagrid column. The class essentially inherits from DataGridTextBoxColumn (although there is one custom class between). Generally speaking everything works beautifully, I bind a dataset to the combobox, it lets the user pick from a list of items, then sets the value in the datagrid.

I've run into one bug though, if the user wishes to add a row to the datagrid they must enter a value in some non-DataGridComboBoxColumn column for the new row to appear. In other words if a user selects a combox value in the bottom, "add-a-row" row, the SetColumnValueAtRow is not sufficient to force the datagrid to actually add a new row. This is a problem because I have some datagrids that only contain DataGridComboBoxColumns, so the user can't add rows to those datagrids. I've tried a workaround (see code in SetColumnValueAtRow) where I add a row to the datasource table then rebind the datagrid, but it seems to have no effect... any thoughts?

The code:
CODE

--------
Notes:
DataGridShowEditableColumn is just DataGridTextBoxColumn with Paint overwritten.
---------------------
#define DEBUG
using System;
using System.Data;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;

namespace AFG.ProductionTracker
{

//code borrowed from MSDN
//http://msdn.microsoft.com/msdnmag/issues/03/08/DataGrids/default.aspx

public class DataGridComboBoxColumn : DataGridShowEditableColumn
{
// Hosted combobox control
private ComboBox comboBox;
private CurrencyManager cm;
private int iCurrentRow;
private int origRowCount;

// Constructor - create combobox,
// register selection change event handler,
// register lose focus event handler
public DataGridComboBoxColumn()
{
this.cm = null;

// Create combobox and force DropDownList style
this.comboBox = new ComboBox();
this.comboBox.DropDownStyle = ComboBoxStyle.DropDownList;

// Add event handler for notification when combobox loses focus
this.comboBox.Leave += new EventHandler(comboBox_Leave);
}

// Property to provide access to combobox
public ComboBox ComboBox
{
get { return comboBox; }
}

// On edit, add scroll event handler, and display combobox
protected override void Edit(System.Windows.Forms.CurrencyManager
source, int rowNum, System.Drawing.Rectangle bounds, bool readOnly,
string instantText, bool cellIsVisible)
{
base.Edit(source, rowNum, bounds, readOnly, instantText,
cellIsVisible);

if (!readOnly && cellIsVisible)
{
// Save current row in the DataGrid and currency manager
// associated with the data source for the DataGrid
this.iCurrentRow = rowNum;
this.cm = source;

// Add event handler for DataGrid scroll notification
this.DataGridTableStyle.DataGrid.Scroll
+= new EventHandler(DataGrid_Scroll);

// Site the combobox control within the current cell
this.comboBox.Parent = this.TextBox.Parent;
Rectangle rect =
this.DataGridTableStyle.DataGrid.GetCurrentCellBounds();
this.comboBox.Location = rect.Location;
this.comboBox.Size =
new Size(this.TextBox.Size.Width,
this.comboBox.Size.Height);

// Set combobox selection to given text
this.comboBox.SelectedIndex =
this.comboBox.FindStringExact(this.TextBox.Text);

// Make the combobox visible and place on top textbox control
this.comboBox.Show();
this.comboBox.BringToFront();
this.comboBox.Focus();
}
}

// Given a row, get the value member associated with a row. Use the
// value member to find the associated display member by iterating
// over bound data source
protected override object
GetColumnValueAtRow(System.Windows.Forms.CurrencyManager source,
int rowNum)
{
// Given a row number in the DataGrid, get the display member
object obj = base.GetColumnValueAtRow(source, rowNum);

// Iterate through the data source bound to the ColumnComboBox
CurrencyManager cm = (CurrencyManager)
(this.DataGridTableStyle.DataGrid.BindingContext[this.comboBox.DataSource]);
// Assumes the associated DataGrid is bound to a DataView or
// DataTable
DataView dataview = ((DataView)cm.List);

int i;

for (i = 0; i < dataview.Count; i++)
{
if (obj.Equals(dataview[i][this.comboBox.ValueMember]))
break;
}

if (i < dataview.Count)
return dataview[i][this.comboBox.DisplayMember];

return DBNull.Value;
}

// Given a row and a display member, iterate over bound data source to
// find the associated value member. Set this value member.
protected override void
SetColumnValueAtRow(System.Windows.Forms.CurrencyManager source,
int rowNum, object value)
{

//workaround for datagrid not adding a row
if(this.origRowCount != source.Count && this.origRowCount != 0)
{
DataTable dt = new DataTable();
dt = (DataTable)this.DataGridTableStyle.DataGrid.DataSource;
DataRow addedRow = dt.NewRow();
//hard code values to test
addedRow["EmployeeID"] = 2;
addedRow["SalesPerson"] = "SAMRAP";
addedRow["JobFunctionID"] = 1;
addedRow["Role"] = "Marketer";
this.DataGridTableStyle.DataGrid.DataSource = dt;
}
this.origRowCount = source.Count;
#if DEBUG
Console.WriteLine(this.origRowCount + " Rows");
#endif

object s = value;

// Iterate through the data source bound to the ColumnComboBox
CurrencyManager cm = (CurrencyManager)
(this.DataGridTableStyle.DataGrid.BindingContext[this.comboBox.DataSource]);
// Assumes the associated DataGrid is bound to a DataView or
// DataTable
DataView dataview = ((DataView)cm.List);
int i;

for (i = 0; i < dataview.Count; i++)
{
if (s.Equals(dataview[i][this.comboBox.DisplayMember]))
break;
}



//if value was changed...
if(!s.Equals(this.TextBox.Text))
{
// If set item was found return corresponding value, otherwise return DbNull.Value
#if DEBUG
Console.WriteLine("Item changed: " + this.cm.Position);
Console.WriteLine("Row " + rowNum.ToString() + " of " + this.cm.List.Count.ToString());
#endif


if(i < dataview.Count)
{s = dataview[i][this.comboBox.ValueMember];}

else
{s = DBNull.Value;}

//call base function to set display and value
base.SetColumnValueAtRow(source, rowNum, s);

}
}

// On DataGrid scroll, hide the combobox
private void DataGrid_Scroll(object sender, EventArgs e)
{
this.comboBox.Hide();
}

// On combobox losing focus, set the column value, hide the combobox,
// and unregister scroll event handler
private void comboBox_Leave(object sender, EventArgs e)
{
DataRowView rowView = (DataRowView) this.comboBox.SelectedItem;
string s = (string) rowView.Row[this.comboBox.DisplayMember];

//fixes bug where ListManager position != currentRow from double Edit call
if(this.cm.Position == this.iCurrentRow)
SetColumnValueAtRow(this.cm, this.iCurrentRow, this.comboBox.Text);
Invalidate();

this.comboBox.Hide();
this.DataGridTableStyle.DataGrid.Scroll -=
new EventHandler(DataGrid_Scroll);
}
}



}




Thanks,
Sam

This post has been edited by Dark_Nexus: 16 Dec, 2006 - 12:02 AM
User is offlineProfile CardPM

Go to the top of the page

wuzzeb
post 24 Jun, 2005 - 10:08 AM
Post #2


New D.I.C Head

*
Joined: 24 Jun, 2005
Posts: 1

Hey. I was also having this problem and found your post on a search on google. I was sad that no one replied with an answer, so I kept hunting for the solution. Eventually, I figured it out ... (I looked through some of the Mono code, and had some breakpoints inside the DataGrid Disassembly to get it...) I thought I would post it here for you and everyone else searching on google.

The problem is the column must call the DataGridColumnStyle.ColumnStartedEditing() function... that is the function that actually creates the row. I just added an event handler on the SelectionChanged event on the combobox. This event handler just called the ColumnStartedEditing() function. As soon as I made that call, it started working. Hope that helps,

John
User is offlineProfile CardPM

Go to the top of the page

Amadeus
post 25 Jun, 2005 - 09:25 AM
Post #3


g++ -o drink whiskey.cpp

Group Icon
Joined: 12 Jul, 2002
Posts: 12,163



Thanked 32 times

Dream Kudos: 25
My Contributions


Thanks for posting John! smile.gif
User is online!Profile CardPM

Go to the top of the page

gcaus
post 14 Dec, 2006 - 06:52 PM
Post #4


New D.I.C Head

*
Joined: 14 Dec, 2006
Posts: 1


My Contributions


What obvious thing am I missing. I am running into the same problem over a year later than this post. Is there a better solution now? I don't understand the details of the reply, sorry.

I can't find a SelectionChanged event on a combo box. What am I missing?

Thanks in advance....

-Jerry

QUOTE(wuzzeb @ 24 Jun, 2005 - 11:08 AM) *

Hey. I was also having this problem and found your post on a search on google. I was sad that no one replied with an answer, so I kept hunting for the solution. Eventually, I figured it out ... (I looked through some of the Mono code, and had some breakpoints inside the DataGrid Disassembly to get it...) I thought I would post it here for you and everyone else searching on google.

The problem is the column must call the DataGridColumnStyle.ColumnStartedEditing() function... that is the function that actually creates the row. I just added an event handler on the SelectionChanged event on the combobox. This event handler just called the ColumnStartedEditing() function. As soon as I made that call, it started working. Hope that helps,

John

User is offlineProfile CardPM

Go to the top of the page

rrue
post 18 Jun, 2008 - 01:33 PM
Post #5


New D.I.C Head

*
Joined: 18 Jun, 2008
Posts: 1

Having the same problem and having some success with this solution. Managed to add the event handler but can't find a way to fire the DataGridColumnStyle() method. What object is it a method of? The DataGrid? Can't reach it from the method I added to the DataGridComboBox class. Managed to make the method in the DataGridComboBox class call a method in my Main_Form class, but still can't see the DataGrid object from there.

Tried making the datagrid public where it's first instantiated (feels sloppy but now I can see it from everywhere, right?). Now I can see it from the methods but not any method ColumnStartedEditing() . If I type it in anyway I get an error 'System.Windows.Forms.DataGrid.ColumnStartedEditing(System.Drawing.Rectangle)' is inaccessible due to its protection level.'

Very new to C# if you haven't guessed already. Anyone else ever solve this?

rrue
Seattle WA USA
User is offlineProfile CardPM

Go to the top of the page

Fast ReplyReply to this topicStart new topic
Time is now: 11/20/08 09:27AM

Live C# Help!

C# Tutorials

Reference Sheets

C# Snippets

Bye Bye Ads

Free DIC T-Shirt

T-Shirt Example

Related Sites

Monthly Drawing

Thumb Drive

Partners

Top Contributors

Top 10 Kudos This Month