TECHNOLOGIES
FORUMS
JOBS
BOOKS
EVENTS
INTERVIEWS
Live
MORE
LEARN
Training
CAREER
MEMBERS
VIDEOS
NEWS
BLOGS
Sign Up
Login
No unread comment.
View All Comments
No unread message.
View All Messages
No unread notification.
View All Notifications
Answers
Post
An Article
A Blog
A News
A Video
An EBook
An Interview Question
Ask Question
Forums
Monthly Leaders
Forum guidelines
samnet
NA
7
0
DataGrid with combobox column bug
May 6 2005 10:53 AM
Hi all, 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: -------- 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
Reply
Answers (
1
)
Click and Double Click Event
Datagrids: How to change Column order?