I've been trying to set the value of an individual DataGridViewComboBoxCell for the last 4 hours and I've been getting nowhere. The most common solution I've seen was to set the .Value member of the DataGridViewComboBoxCell to one of the Items, which I tried and it complained the value was not valid.
DataTable documentTypes = _codedValues.GetCodedValues(Database.DOCUMENT_TYPE_TABLE); documentTypes.Columns[Database.PROFESSION_ID_COLUMN].AllowDBNull = true;
documentTypes.Columns[Database.CODE].AllowDBNull = true;
this.cbxDocumentType.DisplayMember = Database.VALUE;
this.cbxDocumentType.ValueMember = Database.CODE;
this.cbxDocumentType.DataSource = documentTypes.DefaultView;
int rowId = this.dgvDocumentList.Rows.Add(doc.actualName, doc.fileName);
DataGridViewComboBoxCell obj = (DataGridViewComboBoxCell)this.dgvDocumentList.Rows[rowId].Cells[2];
obj.Value = obj.Items[0];
After the message box comes up that tells me DataGridViewComboBoxCell view is not valid, I see the .ToString output of the object being set, which is System.Data.DataRowValue.
Depending what your datasource contains you must use the correct casts to access the correct fields.
Try this:
DataGridViewComboBoxCell cell =
(DataGridViewComboBoxCell)this.dgvDocumentList.Rows[rowId].Cells[2];
cell.Value = ((DataRowView)cell.Items[0]).Row.ItemArray[0];
This assumes that the Items are DataRowViews and that the ValueMember is in the first field.
You can test the type by writing an intermediate step:
var item = cell.Items[0];
And use the debugger to look into the resulting type..
Related
I have a datagridview with a combobox column that is bound to an enum as follows:
var D = (DataGridViewComboBoxColumn)dgvInputs.Columns[2];
D.ValueType = typeof(MyType);
D.ValueMember = "Value";
D.DisplayMember = "Display";
D.DataSource = new MyType[] {
MyType.Rev,
MyType.Model,
MyType.User,
MyType.Status
}.Select(x => new { Display = x.ToString(), Value = (int)x }).ToList();
The datagridview is then bound to a DataTable named ParameterTable:
BindingSource ParamSource = new BindingSource();
ParamSource.DataSource = DataEntry.ParameterTable;
dgvInputs.AutoGenerateColumns = false;
dgvInputs.DataSource = ParamSource;
dgvInputs.Columns[0].DataPropertyName = "Name";
dgvInputs.Columns[1].DataPropertyName = "Prompt";
dgvInputs.Columns[2].DataPropertyName = "Type";
dgvInputs.Columns[3].DataPropertyName = "Width";
dgvInputs.Columns[4].DataPropertyName = "Default Value";
When the user finishes editing the table, I need to validate it. In particular, I need to test that the Type has been defined in each row, and that the Default Value is compatible with the Type.
The problem is, every test I've found for checking if the Type has been set has failed. When I later try to cast the value as MyType as part of testing the default value, I get an error. When I check the .Value property on the empty Type cell in the debugger, it shows a value of "{}".
Currently, I have this code for the test, in the Validating event for the datagridview itself. I have tried various other versions and they have also failed:
foreach (DataGridViewRow Row in dgvInputs.Rows) {
if (!Row.IsNewRow) {
// test other columns ...
DataGridViewComboBoxCell Cell = (DataGridViewComboBoxCell)(Row.Cells[2]);
if (Cell == null || Cell.Value as string == string.Empty) {
// Error ...
}
MyType PType = (MyType)(Cell.Value);
How can I test if a DataGridViewComboBox cell has not been set, and what is this value "{}"?
FYI - I am using VS 2008, and .Net 3.5 SP1. Not my choice. Just what is available to me.
There are a couple problems with this code.
First, D.ValueType = typeof(MyType); is incorrect because from what I see, you are binding to int field. Just remove that line, ValueType will be inferred from the data source.
Now, the main issue. When binding to a data table, the non entered value is represented by DBNull.Value. I would suggest you checking for both null and DBNull.Value. When entered, the value type in your case will be int, but you can safely unbox it to MyType.
The code should be something like this
//...
var value = Row.Cells[2].Value;
if (value == null || value == DBNull.Value)
{
// Error ...
}
else
{
var type = (MyType)value;
// Check if type contains a valid value ...
}
DataSet dsCurrency = new DataSet();
dsCurrency = ParamCurrency.SelectCurrencys();
ddCurrencyField.DataSource = dsCurrency;
ddCurrencyField.DataTextField = "CurrencyName";
ddCurrencyField.DataValueField ="CurrencyCode";
ddCurrencyField.DataBind();
How to select a default value to the dropdownlist control using C#?
If you know the value will exist:
ddCurrencyField.FindItemByText("YourDefaultText").Selected = true;
else
ListItem selectedListItem = ddCurrencyField.Items.FindItemByText("YourDefaultText");
if (selectedListItem != null)
{
selectedListItem.Selected = true;
};
You can also find item by value :
ListItem selectedListItem = ddCurrencyField.Items.FindByValue("YourDefaultValue");
if (selectedListItem != null)
{
selectedListItem.Selected = true;
};
I assume in your datasource object (dsCurrency) is not parsing the default value for the dropdown.
So first you will have to add the default item. After binding the datasource do the following.
ddCurrencyField.Items.Insert(0, new ListItem("-- Select --",0));
With the above code you will have a default/first item selected as "--Select--". If it does not select the first item then simply set the SelectedIndex to 0.
There are 2 ways to set the default item after populating a dropdown.
you can use the "SelectedValue" property
you can use the "SelectedIndex" property
Most of the code samples are given in the previous answers. But I prefer to use the "FindByValue" method.
ddCurrencyField.SelectedIndex = ddCurrencyField.Items.IndexOf(ddCurrencyField.Items.FindByValue(myValue));
If you want to write a safe code please use the second option.
If this dropdown list is a combobox, use this:
ddCurrencyField.SelectedIndex = ddCurrencyField.Items.IndexOf("Wanted Value");
I have combobox with 2 values, ID and Name. I need to get ID from selected item, and I don't know how.
ASPxComboBox1.SelectedItem.GetValue(ID);
Not working.
ASPxComboBox1.TextField = "Name"; //This is the displayMember
ASPxComboBox1.ValueField = "ID"; //This is the valueMember
ASPxComboBox1.ValueType = typeof(String);
ASPxComboBox1.DataSource = DataTableWithIDandNameColumns;
ASPxComboBox1.DataBind();
String theID = Convert.ToString(ASPxComboBox1.Value);//The column in the datasource that is specified by the ValueField property.
OR:
String theID = Convert.ToString(ASPxComboBox1.SelectedItem.GetValue("ID"));//Any column name in the datasource.
Also:
String theName = Convert.ToString(ASPxComboBox1.SelectedItem.GetValue("Name"));
Use ASPxComboBox.Value property.
A combobox can only have one value per item and this is retrieved in your case by:
ASPxComboBox1.Value
See here in the documentation.
Since the value returned will be of type object, you will need to cast this to the type originally set, e.g. String. Then you will be able to work with it.
Usually the problem, when the ASPxComboBox's SelectedItem / SelectedIndex is incorrect, occurs when the ASPxComboBox's ValueType http://documentation.devexpress.com/#AspNet/DevExpressWebASPxEditorsASPxComboBox_ValueTypetopic property is specified incorrectly.
Ensure that the ValueType is set, corresponding to the "Data Type Mappings (ADO.NET)" http://msdn.microsoft.com/en-us/library/cc716729.aspx table.
The combobox displays a blank field by default even though the combobox is populated with a number of values
ColumnSpeed.DataSource = speedList;
ColumnSpeed.ValueType = typeof(string);
I also tried the following, but it still displays the blank text.
foreach (DataGridViewRow row in myDataGridView.Rows)
{
DataGridViewComboBoxCell cell = row.Cells[ColumnSpeed.Index] as DataGridViewComboBoxCell;
if (cell != null)
{
cell.DataSource = speedList;
cell.Value = cell.Items[0].ToString();
}
}
It could be that the ValueMember you assigned to your DataGridView is different from the DisplayMember you assigned. If that's the case, you'll get a blank value, plus you'll get a DataGridError firing.
You should try:
foreach (DataGridViewRow row in dgMain.Rows){
DataGridViewComboBoxCell pkgBoxCell = row.Cells[ColumnSpeed.Index]
pkgBoxCell.Value = ((Package) pkgBoxCell.Items(0)).Id
}
I converted that from vb.net, so it may not compile. In place of the line where i set the value, do whatever steps are necessary to retrieve and set the correct ValueMember value. In my example, I am casting the item to a specific type and using it's id.
I believe the code you have written should work .. just want to know where are you calling the same. It should work if you call it in the databinding_complete event of the grid
Once you set all the DataSources, try calling the DataGridView.Refresh() method. This is usually required to display changes to the DataSources.
I'm using a DataGridView binding its datasource to a List, and specifying the properties for each column.
An example would be:
DataGridViewTextBoxColumn colConcept = new DataGridViewTextBoxColumn();
DataGridViewCell cell4 = new DataGridViewTextBoxCell();
colConcept.CellTemplate = cell4;
colConcept.Name = "concept";
colConcept.HeaderText = "Concept";
colConcept.DataPropertyName = "Concept";
colConcept.Width = 200;
this.dataGridViewBills.Columns.Add(colConcept);
{... assign other colums...}
And finally
this.dataGridViewBills.DataSource=billslist; //billslist is List<Bill>
Obviously Class Bill has a Property called Concept, as well as one Property for each column.
Well, now my problem, is that Bill should have and Array/List/whateverdynamicsizecontainer of strings called Years.
Let's assume that every Bill will have the same Years.Count, but this only known at runtime.Thus, I can't specify properties like Bill.FirstYear to obtain Bill.Years[0], Bill.SecondYear to obtain Bills.Years[1]... etc... and bind it to each column.
The idea, is that now I want to have a grid with dynamic number of colums (known at runtime), and each column filled with a string from the Bill.Years List. I can make a loop to add columns to the grid at runtime depending of Bill.Years.Count, but is possible to bind them to each of the strings that the Bill.Years List contains???
I'm not sure if I'm clear enough.
The result ideally would be something like this, for 2 bills on the list, and 3 years for each bill:
--------------------------------------GRID HEADER-------------------------------
NAME CONCEPT YEAR1 YEAR2 YEAR3
--------------------------------------GRID VALUES-------------------------------
Bill1 Bill1.Concept Bill1.Years[0] Bill1.Years[1] Bill1.Years[2]
Bill2 Bill2.Concept Bill2.Years[0] Bill2.Years[1] Bill2.Years[2]
I can always forget the datasource, and write each cell manually, as the MSFlexGrid used to like, but if possible, I would like to use the binding capabilities of the DataGridView.
Any ideas? Thanks a lot.
I recently ran into this same problem. I ended up using DataGridView's virtual mode instead of binding to a data source. It doesn't have exactly the same features as binding, but it's still a lot more powerful than populating each cell manually.
In virtual mode, the DataGridView will fire an event whenever it needs to display a cell, which essentially means you can populate the cell however you please:
private void my_init_function() {
datagridview.VirtualMode = true;
datagridview.CellValueNeeded += new System.Windows.Forms.DataGridViewCellValueEventHandler(datagridview_CellValueNeeded);
}
private void datagridview_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
e.Value = get_my_data(e.RowIndex, e.ColumnIndex);
}
You could use reflection to set up and fill the DataGridView. I've done this with a single type, but I don't see why it couldn't be extended to your data structure.
To set up the DataGridView:
// Create the columns based on the data in the album info - get by reflection
var ai = new AlbumInfo();
Type t = ai.GetType();
dataTable.TableName = t.Name;
foreach (PropertyInfo p in t.GetProperties())
{
// IF TYPE IS AN ARRAY (OR LIST) THEN ADD A COLUMN FOR EACH ELEMENT
var columnSpec = new DataColumn();
// If nullable get the underlying type
Type propertyType = p.PropertyType;
if (IsNullableType(propertyType))
{
var nc = new NullableConverter(propertyType);
propertyType = nc.UnderlyingType;
}
columnSpec.DataType = propertyType;
columnSpec.ColumnName = p.Name;
dataTable.Columns.Add(columnSpec);
}
dataGridView.DataSource = dataTable;
Then to populate the DataGridView:
// Add album info to table - add by reflection
var ai = new AlbumInfo();
Type t = ai.GetType();
// WOULD NEED TO INCREASE BY LENGTH OF ARRAY
var row = new object[t.GetProperties().Length];
int index = 0;
foreach (PropertyInfo p in t.GetProperties())
{
// IF TYPE IS AN ARRAY (OR LIST) THEN ADD EACH ELEMENT
row[index++] = p.GetValue(info, null);
}
dataTable.Rows.Add(row);
This is just the code I used, so you'll have to modify the code to handle your year array/list.