DataGrid with ComboBox - won't allow me to add more than one new row???

P

PeterZ

G'day,

After doing much searching and pinching bits of ideas from here there and
everywhere I came up with a fairly 'clean' solution of including a comboBox
into a dataGrid column.

You can download a fully working C# sample with the Northwind.mdb here:
www.insightgis.com.au/web/stuff/DataGridCombo.zip


The whole thing works like a charm, but I have a slight problem:

When the user navigates to the new row, fills in some data, subsequent new
rows are not displayed! Meaning you can only add just ONE record! It seems
as if the DataGrid is not detecting changes made by the ComboBox, but if you
physically type some value in through the keyboard then its's happy, it
displays a subsequent new row.

Any ideas what might be causing that?

Here's the code if you don't feel like downloading the ZIP:

(Note, dataAdapers and dataGridColumnStyles have have been configured
through the IDE so you'll need the full source code to make this work)

--------------------------------------------------------------

private void Form1_Load(object sender, System.EventArgs e)
{
dbConnection.ConnectionString = @"provider=Microsoft.Jet.OLEDB.4.0; data
source=C:\NWIND.MDB";

// Load the ORDERS and CUSTOMERS tables from the Northwind demo database.
myDataSet = new DataSet();
daOrders.Fill(myDataSet, "ORDERS");
daCustomers.Fill(myDataSet, "CUSTOMERS");
myDataGrid.DataSource = myDataSet.Tables["ORDERS"];

// Create the comboBox to be used by the 'Customer Name' column in the
grid.
comboCustomers = new ComboBox();
comboCustomers.SelectionChangeCommitted += new
EventHandler(comboCustomers_SelectionChangeCommitted);
comboCustomers.Top = -4; // position the combo so that it's text is
aligned with the cell's text.
comboCustomers.Left = -4;
comboCustomers.DropDownWidth = 150;
comboCustomers.Cursor = Cursors.Arrow;
comboCustomers.DropDownStyle = ComboBoxStyle.DropDownList;

// Set the datasource for the comboBox
comboCustomers.DataSource = myDataSet.Tables["CUSTOMERS"];
comboCustomers.DisplayMember = "CompanyName";
comboCustomers.ValueMember = "CustomerId";

// Databind the combBox to the ORDERS table.
comboCustomers.DataBindings.Add("SelectedValue",
myDataSet.Tables["ORDERS"], "CustomerId");

// Assign the new comboBox to the dataGrid column.
// ... NOTE, I've defined dataGrid column styles through the IDE.
colCustomer.TextBox.Controls.Add(comboCustomers);

// Assign event handler when the user enters the 'Customer Name' cell.
colCustomer.TextBox.Enter += new EventHandler(colCustomer_Enter);
}

private void comboCustomers_SelectionChangeCommitted(object sender,
EventArgs e)
{
// Set the text in the 'Customer Name' datagrid cell (underneath the
comboBox).
myDataGrid[myDataGrid.CurrentCell] = comboCustomers.Text;
}

private void colCustomer_Enter(object sender, EventArgs e)
{
// This event handler is triggered when the user clicks on the 'Customer
Name' cell
// The purpose here is to simply display the comboBox.

if (myDataGrid.ReadOnly)
{
// Don't display the comboBox if dataGrid is readOnly!
comboCustomers.Visible = false;
return;
}

comboCustomers.Width = colCustomer.Width + 3;
comboCustomers.Visible = true;
comboCustomers.BringToFront();
}
 
S

Sijin Joseph

Haven't looked through the code, but make sure you call BeginEdit()
method, when editing starts otherwise you will only get one new row.

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph


G'day,

After doing much searching and pinching bits of ideas from here there and
everywhere I came up with a fairly 'clean' solution of including a comboBox
into a dataGrid column.

You can download a fully working C# sample with the Northwind.mdb here:
www.insightgis.com.au/web/stuff/DataGridCombo.zip


The whole thing works like a charm, but I have a slight problem:

When the user navigates to the new row, fills in some data, subsequent new
rows are not displayed! Meaning you can only add just ONE record! It seems
as if the DataGrid is not detecting changes made by the ComboBox, but if you
physically type some value in through the keyboard then its's happy, it
displays a subsequent new row.

Any ideas what might be causing that?

Here's the code if you don't feel like downloading the ZIP:

(Note, dataAdapers and dataGridColumnStyles have have been configured
through the IDE so you'll need the full source code to make this work)

--------------------------------------------------------------

private void Form1_Load(object sender, System.EventArgs e)
{
dbConnection.ConnectionString = @"provider=Microsoft.Jet.OLEDB.4.0; data
source=C:\NWIND.MDB";

// Load the ORDERS and CUSTOMERS tables from the Northwind demo database.
myDataSet = new DataSet();
daOrders.Fill(myDataSet, "ORDERS");
daCustomers.Fill(myDataSet, "CUSTOMERS");
myDataGrid.DataSource = myDataSet.Tables["ORDERS"];

// Create the comboBox to be used by the 'Customer Name' column in the
grid.
comboCustomers = new ComboBox();
comboCustomers.SelectionChangeCommitted += new
EventHandler(comboCustomers_SelectionChangeCommitted);
comboCustomers.Top = -4; // position the combo so that it's text is
aligned with the cell's text.
comboCustomers.Left = -4;
comboCustomers.DropDownWidth = 150;
comboCustomers.Cursor = Cursors.Arrow;
comboCustomers.DropDownStyle = ComboBoxStyle.DropDownList;

// Set the datasource for the comboBox
comboCustomers.DataSource = myDataSet.Tables["CUSTOMERS"];
comboCustomers.DisplayMember = "CompanyName";
comboCustomers.ValueMember = "CustomerId";

// Databind the combBox to the ORDERS table.
comboCustomers.DataBindings.Add("SelectedValue",
myDataSet.Tables["ORDERS"], "CustomerId");

// Assign the new comboBox to the dataGrid column.
// ... NOTE, I've defined dataGrid column styles through the IDE.
colCustomer.TextBox.Controls.Add(comboCustomers);

// Assign event handler when the user enters the 'Customer Name' cell.
colCustomer.TextBox.Enter += new EventHandler(colCustomer_Enter);
}

private void comboCustomers_SelectionChangeCommitted(object sender,
EventArgs e)
{
// Set the text in the 'Customer Name' datagrid cell (underneath the
comboBox).
myDataGrid[myDataGrid.CurrentCell] = comboCustomers.Text;
}

private void colCustomer_Enter(object sender, EventArgs e)
{
// This event handler is triggered when the user clicks on the 'Customer
Name' cell
// The purpose here is to simply display the comboBox.

if (myDataGrid.ReadOnly)
{
// Don't display the comboBox if dataGrid is readOnly!
comboCustomers.Visible = false;
return;
}

comboCustomers.Width = colCustomer.Width + 3;
comboCustomers.Visible = true;
comboCustomers.BringToFront();
}
 
P

PeterZ

Hi Sijin,

Tried including BeginEdit() but I still don't get additional new rows.

This is the code when I commit the selection in the comboBox:


private void comboCustomers_SelectionChangeCommitted(object sender,
EventArgs e)
{
// Set the text in the 'Customer Name' datagrid cell (underneath the
comboBox).

int colNum = myDataGrid.CurrentCell.ColumnNumber;
int rowNum = myDataGrid.CurrentCell.RowNumber;

myDataGrid.BeginEdit(colCustomer, rowNum);
myDataGrid[myDataGrid.CurrentCell] = comboCustomers.Text;
myDataGrid.EndEdit(colCustomer, rowNum, false);
}


A new row doesn't appear until I physically type in a value in one of the
other columns.



Sijin Joseph said:
Haven't looked through the code, but make sure you call BeginEdit()
method, when editing starts otherwise you will only get one new row.

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph


G'day,

After doing much searching and pinching bits of ideas from here there and
everywhere I came up with a fairly 'clean' solution of including a comboBox
into a dataGrid column.

You can download a fully working C# sample with the Northwind.mdb here:
www.insightgis.com.au/web/stuff/DataGridCombo.zip


The whole thing works like a charm, but I have a slight problem:

When the user navigates to the new row, fills in some data, subsequent new
rows are not displayed! Meaning you can only add just ONE record! It seems
as if the DataGrid is not detecting changes made by the ComboBox, but if you
physically type some value in through the keyboard then its's happy, it
displays a subsequent new row.

Any ideas what might be causing that?

Here's the code if you don't feel like downloading the ZIP:

(Note, dataAdapers and dataGridColumnStyles have have been configured
through the IDE so you'll need the full source code to make this work)

--------------------------------------------------------------

private void Form1_Load(object sender, System.EventArgs e)
{
dbConnection.ConnectionString = @"provider=Microsoft.Jet.OLEDB.4.0; data
source=C:\NWIND.MDB";

// Load the ORDERS and CUSTOMERS tables from the Northwind demo database.
myDataSet = new DataSet();
daOrders.Fill(myDataSet, "ORDERS");
daCustomers.Fill(myDataSet, "CUSTOMERS");
myDataGrid.DataSource = myDataSet.Tables["ORDERS"];

// Create the comboBox to be used by the 'Customer Name' column in the
grid.
comboCustomers = new ComboBox();
comboCustomers.SelectionChangeCommitted += new
EventHandler(comboCustomers_SelectionChangeCommitted);
comboCustomers.Top = -4; // position the combo so that it's text is
aligned with the cell's text.
comboCustomers.Left = -4;
comboCustomers.DropDownWidth = 150;
comboCustomers.Cursor = Cursors.Arrow;
comboCustomers.DropDownStyle = ComboBoxStyle.DropDownList;

// Set the datasource for the comboBox
comboCustomers.DataSource = myDataSet.Tables["CUSTOMERS"];
comboCustomers.DisplayMember = "CompanyName";
comboCustomers.ValueMember = "CustomerId";

// Databind the combBox to the ORDERS table.
comboCustomers.DataBindings.Add("SelectedValue",
myDataSet.Tables["ORDERS"], "CustomerId");

// Assign the new comboBox to the dataGrid column.
// ... NOTE, I've defined dataGrid column styles through the IDE.
colCustomer.TextBox.Controls.Add(comboCustomers);

// Assign event handler when the user enters the 'Customer Name' cell.
colCustomer.TextBox.Enter += new EventHandler(colCustomer_Enter);
}

private void comboCustomers_SelectionChangeCommitted(object sender,
EventArgs e)
{
// Set the text in the 'Customer Name' datagrid cell (underneath the
comboBox).
myDataGrid[myDataGrid.CurrentCell] = comboCustomers.Text;
}

private void colCustomer_Enter(object sender, EventArgs e)
{
// This event handler is triggered when the user clicks on the 'Customer
Name' cell
// The purpose here is to simply display the comboBox.

if (myDataGrid.ReadOnly)
{
// Don't display the comboBox if dataGrid is readOnly!
comboCustomers.Visible = false;
return;
}

comboCustomers.Width = colCustomer.Width + 3;
comboCustomers.Visible = true;
comboCustomers.BringToFront();
}
 
S

Sijin Joseph

Add this code to the comboBox TextChanged event handler, where isEditing
is a bool variable that keeps track of wether the combo is editing
or not. I am also attaching a class that i wrote that creates a custom
combo box column based on the genghis autocomplete combo box control.

private void combo_TextChanged(object sender,EventArgs e)
{
if(!_isEditing)
{
_isEditing = true;
base.ColumnStartedEditing(_combo);
}
}

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph


Hi Sijin,

Tried including BeginEdit() but I still don't get additional new rows.

This is the code when I commit the selection in the comboBox:


private void comboCustomers_SelectionChangeCommitted(object sender,
EventArgs e)
{
// Set the text in the 'Customer Name' datagrid cell (underneath the
comboBox).

int colNum = myDataGrid.CurrentCell.ColumnNumber;
int rowNum = myDataGrid.CurrentCell.RowNumber;

myDataGrid.BeginEdit(colCustomer, rowNum);
myDataGrid[myDataGrid.CurrentCell] = comboCustomers.Text;
myDataGrid.EndEdit(colCustomer, rowNum, false);
}


A new row doesn't appear until I physically type in a value in one of the
other columns.



Haven't looked through the code, but make sure you call BeginEdit()
method, when editing starts otherwise you will only get one new row.

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph


G'day,

After doing much searching and pinching bits of ideas from here there
and
everywhere I came up with a fairly 'clean' solution of including a
comboBox
into a dataGrid column.

You can download a fully working C# sample with the Northwind.mdb here:
www.insightgis.com.au/web/stuff/DataGridCombo.zip


The whole thing works like a charm, but I have a slight problem:

When the user navigates to the new row, fills in some data, subsequent
new
rows are not displayed! Meaning you can only add just ONE record! It
seems
as if the DataGrid is not detecting changes made by the ComboBox, but if
you
physically type some value in through the keyboard then its's happy, it
displays a subsequent new row.

Any ideas what might be causing that?

Here's the code if you don't feel like downloading the ZIP:

(Note, dataAdapers and dataGridColumnStyles have have been configured
through the IDE so you'll need the full source code to make this work)

--------------------------------------------------------------

private void Form1_Load(object sender, System.EventArgs e)
{
dbConnection.ConnectionString = @"provider=Microsoft.Jet.OLEDB.4.0;
data
source=C:\NWIND.MDB";

// Load the ORDERS and CUSTOMERS tables from the Northwind demo
database.
myDataSet = new DataSet();
daOrders.Fill(myDataSet, "ORDERS");
daCustomers.Fill(myDataSet, "CUSTOMERS");
myDataGrid.DataSource = myDataSet.Tables["ORDERS"];

// Create the comboBox to be used by the 'Customer Name' column in the
grid.
comboCustomers = new ComboBox();
comboCustomers.SelectionChangeCommitted += new
EventHandler(comboCustomers_SelectionChangeCommitted);
comboCustomers.Top = -4; // position the combo so that it's text is
aligned with the cell's text.
comboCustomers.Left = -4;
comboCustomers.DropDownWidth = 150;
comboCustomers.Cursor = Cursors.Arrow;
comboCustomers.DropDownStyle = ComboBoxStyle.DropDownList;

// Set the datasource for the comboBox
comboCustomers.DataSource = myDataSet.Tables["CUSTOMERS"];
comboCustomers.DisplayMember = "CompanyName";
comboCustomers.ValueMember = "CustomerId";

// Databind the combBox to the ORDERS table.
comboCustomers.DataBindings.Add("SelectedValue",
myDataSet.Tables["ORDERS"], "CustomerId");

// Assign the new comboBox to the dataGrid column.
// ... NOTE, I've defined dataGrid column styles through the IDE.
colCustomer.TextBox.Controls.Add(comboCustomers);

// Assign event handler when the user enters the 'Customer Name' cell.
colCustomer.TextBox.Enter += new EventHandler(colCustomer_Enter);
}

private void comboCustomers_SelectionChangeCommitted(object sender,
EventArgs e)
{
// Set the text in the 'Customer Name' datagrid cell (underneath the
comboBox).
myDataGrid[myDataGrid.CurrentCell] = comboCustomers.Text;
}

private void colCustomer_Enter(object sender, EventArgs e)
{
// This event handler is triggered when the user clicks on the
'Customer
Name' cell
// The purpose here is to simply display the comboBox.

if (myDataGrid.ReadOnly)
{
// Don't display the comboBox if dataGrid is readOnly!
comboCustomers.Visible = false;
return;
}

comboCustomers.Width = colCustomer.Width + 3;
comboCustomers.Visible = true;
comboCustomers.BringToFront();
}

using System;
using System.Drawing;
using System.Windows;
using System.Windows.Forms;

using Genghis.Windows.Forms;

namespace CHF.Costing.CustomColumnStyles
{
/// <summary>
///
/// </summary>
public class DataGridAutoCompleteComboColumn : DataGridColumnStyle
{
#region Fields
private bool _isEditing = false;
private DataGridCompletionCombo _combo = new DataGridCompletionCombo();
private string oldValue = null;
private const int xMargin = 1;
private const int yMargin = 2;
private DataGrid _grid = null;
#endregion

#region Ctor
public DataGridAutoCompleteComboColumn()
{
_combo.Visible = false;
}
#endregion

#region Public Methods
public void SetItems(object[] items)
{
_combo.Items.AddRange(items);
}
#endregion

#region DataGridColumnStyle Overrides
protected override void Abort(int rowNum)
{
this.EndEdit();
this.RollBack();
}

protected override bool Commit(CurrencyManager dataSource, int rowNum)
{
if (!_isEditing)
{
this.EndEdit();
return true;
}

try
{
object value = this._combo.Text;
base.SetColumnValueAtRow(dataSource, rowNum, value);
}
catch(Exception)
{
Abort(rowNum);
return false;
}
this.EndEdit();
return true;
}

protected override void Edit(CurrencyManager source, int rowNum, System.Drawing.Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible)
{
//If this column is readonly, then don't bother showing the combo
if(base.ReadOnly)
return;

this._combo.Text = this.GetText(base.GetColumnValueAtRow(source, rowNum));

if (cellIsVisible)
{
this._combo.Bounds = bounds;
this._combo.Visible = true;
_combo.TextChanged += new EventHandler(combo_TextChanged);
}
else
{
this._combo.Bounds = bounds;
this._combo.Visible = false;
}

this._combo.RightToLeft = base.DataGridTableStyle.DataGrid.RightToLeft;
this.oldValue = this._combo.Text;
this._combo.Focus();
this._combo.Select(0,_combo.Text.Length);

if (this._combo.Visible)
{
base.DataGridTableStyle.DataGrid.Invalidate(bounds);
}
}

protected override int GetMinimumHeight()
{
return _combo.PreferredHeight + yMargin;
}

protected override int GetPreferredHeight(System.Drawing.Graphics g, object value)
{
return _combo.PreferredHeight + yMargin;
}

protected override System.Drawing.Size GetPreferredSize(System.Drawing.Graphics g, object value)
{
return new Size(0,0);
}

protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle bounds, CurrencyManager source, int rowNum)
{
Paint(g,bounds,source,rowNum,false);
}

protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle bounds, CurrencyManager source, int rowNum, bool alignToRight)
{
string text = GetText(this.GetColumnValueAtRow( source, rowNum ));
Brush bgBrush = null;
Brush fgBrush = null;
if(_grid.IsSelected(rowNum))
{
bgBrush = new SolidBrush( this.DataGridTableStyle.SelectionBackColor );
fgBrush= new SolidBrush( this.DataGridTableStyle.SelectionForeColor );
}
else
{
bgBrush = new SolidBrush( this.DataGridTableStyle.BackColor );
fgBrush= new SolidBrush( this.DataGridTableStyle.ForeColor );
}

g.FillRectangle( bgBrush, bounds );
g.DrawString( text, this.DataGridTableStyle.DataGrid.Font, fgBrush, bounds );
}

protected override void SetDataGridInColumn(DataGrid value)
{
base.SetDataGridInColumn(value);
if (this._combo.Parent != null)
{
this._combo.Parent.Controls.Remove(this._combo);

}

if (value != null)
{
value.Controls.Add(this._combo);

}

_grid = value;
}

protected override void ConcedeFocus()
{
HideCombo();

}
#endregion

#region Helper Methods
protected string GetText(object value)
{
if(value == null)
return this.NullText;
else
return value.ToString();
}

protected void RollBack()
{
this._combo.Text = this.oldValue;
}

protected void HideCombo()
{
this._combo.Visible = false;
}

protected void EndEdit()
{
_combo.TextChanged -= new EventHandler(combo_TextChanged);
HideCombo();
_isEditing = false;
base.Invalidate();
}
#endregion

#region ComboBox Event Handlers
private void combo_TextChanged(object sender,EventArgs e)
{
if(!_isEditing)
{
_isEditing = true;
base.ColumnStartedEditing(_combo);
}
}
#endregion
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top