I have a DataGridView that contains a combo box (DataGridViewComboBoxColumn). This combo box is populated with a set of setup values. These setup values can be inactivated such that only active values are displayed in the combo box, however, existing entries(records) that use the inactive values must still be displayed.
I can successfully loop over the items in the grid and if a record has a value that is no longer active (i.e. part of the DataGridViewComboBoxCell items), I simply add it to the items for that DataGridViewComboBoxCell.
Problem:
I am unable to find a place to put this code such that I do not get the dreaded 'DataGridViewComboBoxCell value is not valid.'
For example, I can put this code into the Paint event of the DataGridView and the grid functions perfectly. No issues with editing/updating values nor do I have any issues in terms of display (inactive value is always shown)... However, it still throws the 'DataGridViewComboBoxCell value is not valid.' error.
Question:
Where can I add code (or how) to add an 'inactive' value after the active values have been added to the combo box (DataGridViewComboBoxColumn), but before the records are bound to avoid getting this error?
What about just catching the datagridview error and doing nothing with it.
void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
e.Cancel = true;
}
// Add code in user interface
dataGridView1.DataError +=
new DataGridViewDataErrorEventHandler(dataGridView1_DataError);
Related
I'm trying to replicate this behavior in the ColumnMappings window from SQL Management Studio:
Image Here
When you click inside a destination cell, the type changes from text
to combobox (it seems), and when you leave the cell, it takes the selected value from the combobox and changes back to textboxCell with the value included.
It does this for every cell in that column.
So, when I load the data, all the cells are textbox, and when the user enters any cell in that column, I do this:
private void dgvwMapping_CellEnter(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 1)
{
string txt = dgvwMapping[e.ColumnIndex, e.RowIndex].Value.ToString();
DataGridViewComboBoxCell cbbxDestination = new DataGridViewComboBoxCell() { DataSource = new List<string>(someList) };
cbbxDestination.Value = txt;
dgvwMapping[e.ColumnIndex, e.RowIndex] = cbbxDestination;
}
}
So far so good, if I change from cell to cell everything goes fine, except when I click the cell that has the coordinates [1,1]. The only one that throws the "Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore" exception is the one with the columnIndex equal to the rowIndex.
I already tried wrapping the line where I reassign the Cell Type in an invoke call, like this:
dgvwMapping.BeginInvoke(new MethodInvoker(delegate ()
{
dgvwMapping[e.ColumnIndex, e.RowIndex] = cbbxDestination;
}));
But It loops indefinitely the event. Even wrapping all the code inside the event makes the event loop indefinitely.
I haven't coded anything inside the CellEndEdit or the CellLeave yet.
Does anyone have any advice? Perhaps my aproach at replicating that behavior is not the best.
Thanks
Your issue:
When you click inside a destination cell, the type changes from text to combobox (it seems), and when you leave the cell, it takes the selected value from the combobox and changes back to textboxCell with the value included.
is just a simple style setting for the DataGridViewComboBoxColumn property:
yourGridColumnComboBox.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
This will make it appear like a TextBox, but when it has focus with selectable items, it will show the drop down button.
C#, WinForms, DataGridView, DataTable. My form allows the user to enter data into a new row (as opposed to, say, popping up a single record view of the record). When the user clicks my Save button, the click event looks like this:
DataTable dtAddRows = this.SomeFictitiouslyNamedDataSet.SomeFictitiouslyNamedDataTable.GetChanges(DataRowState.Added);
My assumption is that calling GetChanges with that enum is going to get me a set of the rows that were added to the grid at run time. However, it errors out because 1 of the columns "Last_Updated_DT" (which must be displayed and readonly) is a date column that will be populated when we write to the datatable. However, the DataSet has a rule that this column cannot be null.
The problem is, I get an error indicating that the Last_Updated_DT column is actually null (surprise surprise). Its a new row, and the column is readonly in the grid, so of course it is null.
How do I get around this error or stuff a value in that (or those) rows for that column before I actually try to get the added rows?
For the sake of posterity:
private void myGrid_DefaultValuesNeeded(object sender, DataGridViewRowEventArgs e)
{
e.Row.Cells["MyColumnNameGridViewTextBoxColumn1"].Value = String.Empty;
}
Adding that event to my code fixed my issue. I set the value to String.Empty so it wouldnt put a date/time value in the column until after the Save was clicked.
Then, in the Save_Click event, I get the added rows with this code:
DataTable dtAddedRows = this.dsMyDataSet.MyDataTable.GetChanges(DataRowState.Added);
Then, in the TableAdapter.Insert parameter list, I added DateTime.Now for the date parameter.
Eventually call MyTableAdapter.Update method using the DataSet overload.
All fixed.
Hat tip to #KiNeTiC for providing the necessary guidance.
I keep getting an error that states DataGridViewComboBox value is not valid. It seems like it is also in an endless loop: I will click ok and it will continuously keep popping up. I am running a program with a windows form application written in C# and .NET. Does anyone know how to fix this error?
Here is some portions of my code:
// authorityTypeDataGridViewTextBoxColumn
//
this.authorityTypeDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.DisplayedCells;
this.authorityTypeDataGridViewTextBoxColumn.DataPropertyName = "AuthorityType";
this.authorityTypeDataGridViewTextBoxColumn.DataSource = this.AuthorityTypeBindingSource;
this.authorityTypeDataGridViewTextBoxColumn.DisplayMember = "Description";
this.authorityTypeDataGridViewTextBoxColumn.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;
this.authorityTypeDataGridViewTextBoxColumn.Frozen = true;
this.authorityTypeDataGridViewTextBoxColumn.HeaderText = "AuthorityType";
this.authorityTypeDataGridViewTextBoxColumn.MaxDropDownItems = 100;
this.authorityTypeDataGridViewTextBoxColumn.Name = "authorityTypeDataGridViewTextBoxColumn";
this.authorityTypeDataGridViewTextBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True;
this.authorityTypeDataGridViewTextBoxColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
this.authorityTypeDataGridViewTextBoxColumn.ValueMember = "Value";
this.authorityTypeDataGridViewTextBoxColumn.Width = 121;
//
// AuthorityTypeBindingSource
//
this.AuthorityTypeBindingSource.DataMember = "AuthorityType";
this.AuthorityTypeBindingSource.DataSource = this.lookUpDataSet;
Does anyone have any suggestions?
Here is the Handler:
private void TaskSummaryGrid_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
MessageBox.Show(this, e.Exception.Message);
e.Cancel = true;
}
yeah the solution is to make datagridviewcombobox cell value the same you are getting in the code behind.
if i want to show typeof(int) value , i must set property of the datagridviewcombobox cell like:
this.ComboboxCellcolumnName.ValueType = typeof(int);
the value type that you got(e.g int) should be the same you want to show in the combobox cell (int).
It looks like your DataGridViewTextBoxColumn at some point was a DataGridViewComboBoxColumn, because you have ComboBox properties that do not belong to a TextBox column.
The DataGridViewTextBoxColumn does not have:
.DataSource = this.AuthorityTypeBindingSource;
.DisplayMember = "Description";
.DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox;
.MaxDropDownItems = 100;
.ValueMember = "Value";
I can only guess editing the designer file by hand can cause this.
If, however, you wanted to revert back to your combo box column, you would need to set some special handling to set it up.
You can refer to the MSDN article here, or this example below:
MSDN: Binding Enums to DataGridViews
InitializeComponent();
// special setup for enum column
DataGridViewComboBoxColumn stateColumn = dgLedger.Columns[0] as DataGridViewComboBoxColumn;
if (stateColumn != null)
{
stateColumn.DataSource = Enum.GetValues(typeof(TransactionState));
}
_ledger = new BindingList<LedgerItem>();
dgLedger.DataSource = _ledger;
I just had a similar experience with one of my datagridviews: DataError was getting thrown non-stop... It eventually turned out to be because the id in the combobox DataSource was of a different type (bigint) than the column that referenced it (int)...
I used all the solution above but none of them worked, so I tried to override the DataError event and it works very well without any problem:
private void dgv_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
//do nothing
}
Ten years later now, I recently ran into the same problem and ended up working through the datagridview combobox source code to understand the problem and the solution. It turns out that even though swallowing error events is rarely the right course, #mamoun was correct: capturing the error and discarding it may be the correct solution in some scenarios. Here's why.
In a DataGridView with a ComboBox column, when grid data is loaded and the data in the grid column bound to the combobox value cannot be validated, a data error event is raised.
This can be tricky because the comboBox value is bound to a column in the DGV that may not be the same column in which the combobox itself appears (e.g., it may be a hidden column or another column that reflects the combobox value).
Validation can fail due to dev errors such as type mismatch, of course, but a common reason for failure is a scenario in which the dropdown data source is fixed (non-editable and does not allow adding new rows) and the datasource has delivered data in the value column that does not match any existing entry in the dropdown. This may occur, for example, if some of the data was originally entered as free-text and was misspelled, or if data is round-tripping to another system that changes white space or capitalization. It may occur if you change the list feeding the dropdown.
In this scenario, catching and ignoring (or preferably logging) the event will cause the value that triggered the error to be replaced with the default value from the combobox (usually the first row of the dropdown). If this is the desired handling, swallow away!
I wasn't able to find another event that allowed detection and correction to be carried out before the error event fires. In particular, the CellValidating event does not fire in this scenario.
I have two Comboboxes where the second one is dependent upon the first one.
When the SelectedIndexChanged event of the first Combobox fires then the second Combobox will be enabled.
After the event, the second Combobox is enabled but I cannot select the ComboBox item.
EDIT
I use Dev express Tools
First Combo I load in Page_Load Event
I use Server Side code:
protected void ASPxComboModule_SelectedIndexChanged(object sender, EventArgs e)
{
LoadSecondCombo();
LoadSecondCombo.Focus();
}
There is no problem in loading, but I'm unable to select 2nd combo item.
What do this do: LoadSecondCombo(); I assume it returns an instance of the control. Where does it set combo.Enabled at?
LoadSecondCombo(); LoadSecondCombo.Focus();
look like method that reference your comboBox and Load it.
When you want to focus LoadSecondCombo should ne an instance of Combo Box. I think it is not and so your combo is not selected.
Can you try going back a bit and look at the Id of combo Box (if it in a composit control like DataGrid / View you will have to do a FindControl) and then focus. I mean typing
comboBtn1.Focus();
Now if that works then you know that your control can be found. In that case mofidify the LoadSescondCombo() to return an instance of combo button if it is not doing so already.
then create a reference to that combobutton by
ComboButton cbtn = LoadSecondCombo(); and
cbtn.Focus();
i had two combobox(Catogery, product) in my grid.
what i want to do is.
if i select category it will display some data set value based on category,
and if i select product it will bind some values in that datagrid cells.like price quantity..
i don't have idea about how to write event for combo box selected index change event which is inside the grid.
Handle the CellEndEdit event on the DataGridView. You'll have to test that the sender is the correct DataGridViewComboBoxColumn, read the value, and use that to bind the other DataGridViewComboBoxColumn to the appropriate data source.
I'm not sure about that, because I don't have visual studio at the moment. But there must be an event called RowCellValueChanged event, write your code in this event, hand row index with EventArgs e and set your values to row which you have an index of row.