Set dynamically combobox values on Datagridview - c#

I'm trying to set a combobox value dynamically from a query with the following code and it's displayed only when I click on the combobox column, if I don't click the value disappears and it's not set.
The first 5 values are related to the user and the one displayed on the combobox might be not set into database, so it might be null if it doesn't exist or Type "A" or "C".
This is image is before clicking on the cell
This image is after clicking the cell with data loaded
This image is after the cell is unclicked and selected any other cell
//This code is used to Build combobox column after the data is binded
var items = new[] { new Logica.Items { valor = "C", texto = "Creador" }, new Logica.Items { valor = "A", texto = "Aprobador" } };
DataGridViewComboBoxColumn cell = new DataGridViewComboBoxColumn();
cell.DataSource = items;
cell.ValueMember = "valor";
cell.DisplayMember = "texto";
this.dataGridView1.Columns.Insert(5, cell);
this.dataGridView1.Columns[5].HeaderText = "TipoUsuario";
for (int i = 0; i < this.dataGridView1.RowCount; i++)
{
string valor = dataGridView1[0, i].Value.ToString();//get the first datagridview value
if (valor != null || valor != "")
{
string orgv = string.Empty + this.dataGridView1[0, i].Value.ToString().ToUpper();//required to fill combobox conditions
string veg = string.Empty + this.dataGridView1[1, i].Value.ToString().ToUpper();//required to fill combobox conditions
string aprobador = string.Empty + this.dataGridView1[3, i].Value.ToString().ToUpper();//required to fill combobox conditions
DataTable ds = cargarnodos("LLenaTipoUsuario"); // this query into db to get the combobox values if this exists, if not then it's null.
foreach (DataRow datar in ds.Rows)
{
if (orgv == datar["VKORG"].ToString() && veg == datar["VTWEG"].ToString() && aprobador == datar["idAprobador"].ToString())
{
string seleccion = datar["TipoUsuario"].ToString().ToUpper();
this.dataGridView1[5, i].Value = seleccion; // this changes value
MessageBox.Show(dataGridView1[5, 0].Value.ToString());
break;
}
}
}

I managed to get the rows to display the data in the cell even if the row is selected or not. This was done by setting the DataPropertyName of the ComboBoxColumn.
cell.DataPropertyName = "valor"; //
This should be data column should be available in corresponding to the Datasource of the parent DataGridView and their data types are identical..
Further if this column in the can contain null, you add the following line (if you are allowing the user to select/change etc)
cell.DefaultCellStyle.NullValue = "-- Select -- ";

In my case, while loading the form is not possible to set the combobox values. After the datagridview is binded, it's needed to use the following command to edit values based on previous selections.
dataGridView1.DataBindingComplete += new DataGridViewBindingCompleteEventHandler(selecciongv_DataBindingComplete); // selecciongv is the method to do the same proccess.

Related

how to remove ComboBoxes from the previous selection

I create method that when a user selects a db table from the combobox, a number of new comboboxes will be generated with each of them shows the table column name. The problem is when I select the second or third db table, the column names associated with those tables are not showed. Instead, the columns of the first table remain exist. Could someone suggest how to remove the comboboxes from the previous selection and show the new ones?
private void cboTable_SelectedIndexChanged(object sender, EventArgs e)
{
string tableName = cboTable.SelectedItem.ToString();
List<string> columnList = GetDatabaseList(tableName);
int i = 0;
foreach (var column in columnList)
{
ComboBox cb = new ComboBox();
cb.Location = new Point(475, 25 * i + 235);
this.Controls.Add(cb);
cb.Items.Add(column);
cb.SelectedIndex = -1;
cb.Refresh();
cb.SelectedIndex = 0;
i++;
}
}

How can I add a Drop Down List into every cell for a specific column in a DataGridView in C#

I am trying to add a drop down list into all cells for a column in a datagridView in my Winforms Application. I have created the view programatically by dragging the dgv into the form, and adding columns upon the creation of the class.
The drop down list appears in my DGV column, however when I click on the list nothing opens up - i am unsure if the ComboBox is populated and not opening, or if it simply does not contain values for user to select. Hovering over the object when adding the comboBox to the cell, i can see the item array populated with my values..
Please advise on how I can allow the user to select values in the cell that are populated from my list
DataGridViewTextBoxColumn diffKey = new DataGridViewTextBoxColumn();
DataGridViewComboBoxColumn matchDesc = new DataGridViewComboBoxColumn();
DataGridViewTextBoxColumn permDiff = new DataGridViewTextBoxColumn();
grdEditAnnot.Columns.Add(diffKey);
grdEditAnnot.Columns.Add(matchDesc);
grdEditAnnot.Columns.Add(permDiff);
DataGridViewComboBoxCell matchDescDropbox = new DataGridViewComboBoxCell();
List<string> lstMatchDesc = new List<string>();
LoadMatchDescriptions(out lstMatchDesc);
foreach (string ddlItem in lstMatchDesc)
{
matchDescDropbox.Items.Add(ddlItem);
}
grdEditAnnot.Rows.Add(2);
matchDescDropbox.DataSource = GetMatchDescDDL(); // Bind combobox with datasource.
matchDescDropbox.ValueMember = "Description";
matchDescDropbox.DisplayMember = "Description";
grdEditAnnot.Rows[0].Cells[1] = matchDescDropbox;
}
private DataTable GetMatchDescDDL()
{
DataTable l_dtDescription = new DataTable();
l_dtDescription.Columns.Add("Description", typeof(string));
List<string> matchDescLst;
if (LoadMatchDescriptions(out matchDescLst) == 0)
{
foreach(string matchDesc in matchDescLst)
{
l_dtDescription.Rows.Add(matchDesc);
}
}
return l_dtDescription;
}
private int LoadMatchDescriptions(out List<string> matchDscLst)
{
//string SQL = SQL USED TO POPULATE MY LIST
//a temporary list of test strings would work to show how to get this to work... ex: list of test1, test2, test3 etc
try
{
matchDscLst = new List<string>();
rdr.ExecuteSQL(SQL);
while ((rec = rdr.FetchNextRecord()) != null)
{
matchDscLst.Add(rec.GetStringVal(0));
}
return 0;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error Loading Match Descriptions", MessageBoxButtons.OK, MessageBoxIcon.Error);
matchDscLst = new List<string>();
return -1;
}
}
This is my first post on StackOverflow; apologies if this is not in best format or if we need more info..
Result of code:
Grid that is created; user cannot open up comboBox or type into textbox columns
use DataGridViewComboBoxCell
look this example :
https://www.aspsnippets.com/Articles/Add-ComboBox-to-DataGridView-in-Windows-Forms-Application-using-C-and-VBNet.aspx

ComboBox added programmatically to DataGridView cell not expanding on cell click

I have a DataGridView in a C# WinForms project in which, when the user clicks on certain DGV cells, the cell changes to a DataGridViewComboBoxCell and the ComboBox is populated with some values for the user to select. Here's the form code for the DataGridView_Click event:
private void dgvCategories_Click(Object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 5 && !(dgvCategories.Rows[e.RowIndex].Cells[e.ColumnIndex].GetType().Name == "DataGridViewComboBoxCell"))
{
// Bind combobox to dgv and than bind new values datasource to combobox
DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();
// Get fields to build New Value query
List<string> lsNewValuesResult = new List<string>();
string strCategory = dtCategories.Rows[e.RowIndex][1].ToString();
string strCompanyName = cboSelectCompany.Text;
string strQueryGetNewValuesValidationInfo = "SELECT validationdb, validationtable, validationfield, validationfield2, validationvalue2" +
" FROM masterfiles.categories" +
" WHERE category = #category";
//" WHERE category = '" + strCategory + "'";
// Pass validation info query to db and return list of New Values
db getListOfNewValues = new db();
lsNewValuesResult = getListOfNewValues.GetNewValuesList(strQueryGetNewValuesValidationInfo, strCategory, strCompanyName);
//Populate the combobox with the list of New Values
foreach (string strListItem in lsNewValuesResult)
{
cboNewValueList.Items.Add(strListItem);
}
//
dgvCategories[e.ColumnIndex, e.RowIndex] = cboNewValueList;
}
}
Here's the code in the db class that populates the ComboBox (this likely isn't necessary to include for the purposes of this question, but for the sake of completeness, I'm including it, in case is it relevant):
public List<string> GetNewValuesList(string strValidationInfoQuery, string strCategory, string strCompanyName)
{
List<string> lsValidationInfo = new List<string>();
List<string> lsNewValuesList = new List<string>();
using (NpgsqlConnection conn = new NpgsqlConnection(connString))
using (NpgsqlCommand cmd = new NpgsqlCommand(strValidationInfoQuery, conn))
{
cmd.Parameters.AddWithValue("category", strCategory);
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
int intReaderIndex;
for (intReaderIndex = 0; intReaderIndex <= reader.FieldCount - 1; intReaderIndex++)
{
// reader indexes 3 & 4 correspond to categories.validationfield2 and validationvalue2, which can be null
if (string.IsNullOrEmpty(reader[intReaderIndex].ToString()))
{
lsValidationInfo.Add("");
}
else
{
lsValidationInfo.Add(reader.GetString(intReaderIndex));
}
//Console.WriteLine("reader index " + intReaderIndex + ": " + reader.GetString(intReaderIndex));
}
}
}
}
string strValidationDb = lsValidationInfo[0];
string strValidationTable = lsValidationInfo[1];
string strValidationField = lsValidationInfo[2];
string strValidationField2 = lsValidationInfo[3];
string strValidationValue2 = lsValidationInfo[4];
string strQueryGetNewValues = "SELECT DISTINCT " + strValidationField +
" FROM " + strValidationDb + "." + strValidationTable +
" WHERE company_id = (SELECT id FROM company WHERE name = '" + strCompanyName + "')";
if (!string.IsNullOrEmpty(strValidationField2) && !string.IsNullOrEmpty(strValidationValue2)) strQueryGetNewValues += " AND " + strValidationField2 + " = '" + strValidationValue2 + "'";
strQueryGetNewValues += " ORDER BY " + strValidationField;
using (NpgsqlConnection conn = new NpgsqlConnection(connString))
using (NpgsqlCommand cmd = new NpgsqlCommand(strQueryGetNewValues, conn))
{
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
int intReaderIndex;
for (intReaderIndex = 0; intReaderIndex <= reader.FieldCount - 1; intReaderIndex++)
{
// reader indexes 3 & 4 correspond to categories.validationfield2 and validationvalue2, which can be null
if (string.IsNullOrEmpty(reader[intReaderIndex].ToString()))
{
lsNewValuesList.Add("");
}
else
{
lsNewValuesList.Add(reader.GetString(intReaderIndex));
}
Console.WriteLine("reader index " + intReaderIndex + ": " + reader.GetString(intReaderIndex));
}
}
}
}
return lsNewValuesList;
}
The combobox is getting populated, as I can access the items in lsNewValuesResult in the _Click method. The DGV Edit Mode is set to EditOnEnter. I tried EditOnKeystroke, but that didn't cause the combobox to expand on mouse click.
This is what the combobox looks like when the cell is clicked on and the CBO is populated and added to the DGV cell:
That's after I clicked each of the two cells.
[RESOLVED]
See my Answer below.
Unfortunately solving this revealed a new issue.
I'm about to publicly admit that I'm stupid:
For design and functionality reasons that are required for this project, I am manually setting the widths and names of the DGV's columns, and I also need the 2nd through 4th columns ReadOnly = true. Well, I inadvertently set the 5th column - the column that this question is about to ReadOnly = true as well.
Thank you all for your attempts at answering. This just serves to remind us how something so simple can cause a seemingly big issue and is so easy to overlook!
If I recognize your problem correctly, in my test app i add a DataGridView whit 6 column, EditMode = EditOnEnter
(Others need three time click to open dropdown, As far as I tried) and handle CellStateChanged envent.
private void dgvCategories_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
{
if (e.StateChanged == DataGridViewElementStates.Selected)
{
DataGridViewCell cell = e.Cell;
int columnIndex = cell.ColumnIndex;
int rowIndex = cell.RowIndex;
//---IF CONDITIONS--
//columnIndex == 5
// Only cells in Columns[5]
//cell.Selected
// Because this event raised two time, first for last selected cell and once again
// for currently selected cell and we need only currently selected cell.
//cell.EditType.Name != "DataGridViewComboBoxEditingControl"
// If this cell "CellStateChanged" raised for second time, only other cell types allowed
// to edit, otherwise the current cell lost last selected item.
if (columnIndex == 5 && cell.Selected && cell.EditType.Name != "DataGridViewComboBoxEditingControl")
{
DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();
//Add items to DataGridViewComboBoxCell for test, replace it with yours.
for (int i = 0; i < 10; i++)
cboNewValueList.Items.Add($"Item {i}");
dgvCategories[columnIndex, rowIndex] = cboNewValueList;
}
}
}
NOTE: user must click two time in a cell to open drop down menu.
Edit One: As Reza Aghaei suggest for single click in cell:
private void dgvCategories_CellClick(object sender, DataGridViewCellEventArgs e)
{
DataGridViewComboBoxEditingControl editingControl = dgvCategories.EditingControl as DataGridViewComboBoxEditingControl;
if (editingControl != null)
editingControl.DroppedDown = true;
}
You might need to turn AutoGenerateColumns off:
Also, it seems to take a three clicks for the dropdown to pop.
public Form1()
{
InitializeComponent();
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = GetDataSource();
DataGridViewComboBoxColumn dgvcbc = new DataGridViewComboBoxColumn();
dgvcbc.Items.Add("R0C0");
dgvcbc.Items.Add("R1C0");
dgvcbc.Items.Add("R2C0");
dgvcbc.Items.Add("R3C0");
dgvcbc.DataPropertyName = "Col0";
dataGridView1.Columns.Add(dgvcbc);
}
DataTable GetDataSource()
{
var dtb = new DataTable();
dtb.Columns.Add("Col0", typeof(string));
dtb.Columns.Add("Col1", typeof(string));
dtb.Columns.Add("Col2", typeof(string));
dtb.Columns.Add("Col3", typeof(string));
dtb.Columns.Add("Col4", typeof(string));
dtb.Rows.Add("R0C0", "R0C1", "R0C2", "R0C3", "R0C4");
dtb.Rows.Add("R1C0", "R1C1", "R1C2", "R1C3", "R1C4");
dtb.Rows.Add("R2C0", "R2C1", "R2C2", "R2C3", "R2C4");
dtb.Rows.Add("R3C0", "R3C1", "R3C2", "R3C3", "R3C4");
return dtb;
}
Are you maybe getting an error which is not being shown for some reason?
If I use your code, DataGridViewComboBoxCell seems to be populated with values, but I get DataGridViewComboBoxCell value is not valid runtime error.
This test code is working fine for me:
private void dgvCategories_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();
List<string> lsNewValuesResult = new List<string>();
lsNewValuesResult.Add("Value1");
lsNewValuesResult.Add("Value2");
lsNewValuesResult.Add("Value3");
foreach (string strListItem in lsNewValuesResult)
{
cboNewValueList.Items.Add(strListItem);
}
dgvCategories[e.ColumnIndex, e.RowIndex] = cboNewValueList;
// Added setting of initial value
cboNewValueList.Value = cboNewValueList.Items[0];
}
So maybe try setting the initial value for your DataGridViewComboBoxCell after you add it to the DataGridView.
You can consider the following facts about DataGridView:
If you set AutoGenerateColumns to false, then you need to add columns to Columns collection manually.
If you set AutoGenerateColumns to true, when you assign the data to DataSource, the control generates columns automatically for the data source. In this case, the control looks in list of columns of the data source and for each column if there's no column in the Columns collection of the control having the same DataPropertyName as data source's column name, it will add a column to Columns collection.
DataPropertyName of the datagridviews' columns determines the bound column of the data source.
You usually want to add DataGridViewXXXXColumn to columns collection rather than using a DataGridViewXXXXCell for a cell.
If you set EditMode to EditOnEnter, then if you click on dropdown button, one click is enough. If you click on cell content, two clicks is needed.
If you would like to make it single click even if you click on cell content, take a look at this post. (Note: I haven't used this is the example, it's a bit annoying.)
you can set DisplayStyle to Nothing, then it shows the column as a combo box, just in edit mode.
A basic example on using DataGridViewComboBoxColumn
I suppose you are going to show a list of Products having (Id, Name, Price, CategoryId) in a DataGridView and the CategoryId should come from a list of Categories having (Id, Name) and you are going to show CategoryId as a ComboBox.
In fact it's a basic and classic example of DataGridViewComboBoxColumn:
private void Form1_Load(object sender, EventArgs e) {
var categories = GetCategories();
var products = GetProducts();
var idColumn = new DataGridViewTextBoxColumn() {
Name = "Id", HeaderText = "Id", DataPropertyName = "Id"
};
var nameColumn = new DataGridViewTextBoxColumn() {
Name = "Name", HeaderText = "Name", DataPropertyName = "Name"
};
var priceColumn = new DataGridViewTextBoxColumn() {
Name = "Price", HeaderText = "Price", DataPropertyName = "Price"
};
var categoryIdColumn = new DataGridViewComboBoxColumn() {
Name = "CategoryId", HeaderText = "Category Id", DataPropertyName = "CategoryId",
DataSource = categories, DisplayMember = "Name", ValueMember = "Id",
DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing
};
dataGridView1.Columns.AddRange(idColumn, nameColumn, priceColumn, categoryIdColumn);
dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = products;
}
public DataTable GetProducts() {
var products = new DataTable();
products.Columns.Add("Id", typeof(int));
products.Columns.Add("Name", typeof(string));
products.Columns.Add("Price", typeof(int));
products.Columns.Add("CategoryId", typeof(int));
products.Rows.Add(1, "Product 1", 100, 1);
products.Rows.Add(2, "Product 2", 200, 2);
return products;
}
public DataTable GetCategories() {
var categories = new DataTable();
categories.Columns.Add("Id", typeof(int));
categories.Columns.Add("Name", typeof(string));
categories.Rows.Add(1, "Category 1");
categories.Rows.Add(2, "Category 2");
return categories;
}
Learn more
To learn more about DataGridView, take a look at DataGridView Control (Windows Forms). It contains links to some documentations and useful How To articles, including:
DataGridView Control Overview
Basic Column, Row, and Cell Features in the Windows Forms DataGridView Control
Basic Formatting and Styling in the Windows Forms DataGridView Control
Column Types in the Windows Forms DataGridView Control

c# how to set several combobox column in datagridview

I have been able to make one existing column combo box column in the datagridview, how do I do it for several columns? Also how do I add existing distinct records in the combobox items? The user will be able to either choose value from combobox item or write their own. So far my code is:
dgvLoadTable.DataSource = null;
var context = new CadAdminEntities();
var TableName = cboSelectTable.Text.ToString();
var rawData = context.GetType().GetProperty(TableName).GetValue(context, null);
var truncatedData = ((IQueryable<object>)rawData).Take(0);
var source = new BindingSource { DataSource = truncatedData };
dgvLoadTable.DataSource = source;
dgvLoadTable.ReadOnly = false;
dgvLoadTable.AllowUserToAddRows = true;
DataGridViewComboBoxCell dgvCol = new DataGridViewComboBoxCell();
for (int row= 0; row < dgvLoadTable.Rows.Count; row++)
{
for (int col = 0; col < dgvLoadTable.Columns.Count; col++)
{
if(col==2||col==4)
this.dgvLoadTable[col,row] = dgvCol;
//This part throws error, as there is only one combobox
}
}
dgvLoadTable.Refresh();
This is easy to fix:
this.dgvLoadTable[col, row] = new DataGridViewComboBoxCell();
will create a fresh ComboBoxCell for each case.
You can delete the line
DataGridViewComboBoxCell dgvCol = new DataGridViewComboBoxCell();
Note that since you have a Databound DGV and the Columns were probably created automatically, you should keep in mind, that often one needs to switch off that automatism and create all column manually before setting the DataSource..

DataGridView - ComboBox # runtime

I have a DataGridView where I set the DataSource to a collection of objects when the tab the DataGridView resides is selected.
After the datasource is set I'd like to change the "County" column to a DataGridViewComboBoxColumn with the state's counties as the items. Nothing I've seen works yet - it always gives an exception.
Is there a way to change the column type without deleting it?
Is there a way to have a combobox or other control appear when I click on a cell in that row without having to modify the column type?
======================== My Failing Code ========================
//ii is a for loop variable on the dataGridViewFields.Columns.Count
string colName = dataGridViewFields.Columns[ii].Name;
if (colName.Equals("County"))
{
string dpName = dataGridViewFields.Columns[ii].DataPropertyName;
DataGridViewComboBoxColumn column = new DataGridViewComboBoxColumn();
//get current column characteristics.
column.ValueType = dataGridViewFields.Columns[ii].ValueType; ;
column.Name = dataGridViewFields.Columns[ii].Name;
column.HeaderText = dataGridViewFields.Columns[ii].HeaderText;
column.Width = dataGridViewFields.Columns[ii].Width;
//remove column from grid
dataGridViewFields.Columns.RemoveAt(ii);
//set column combobox characteristics
column.DropDownWidth = 160;
column.MaxDropDownItems = 10;
column.Items.AddRange(new string[] {"Dane", "Dodge", "Door"});
column.FlatStyle = FlatStyle.Flat;
DataGridViewCell cell = new DataGridViewComboBoxCell();
cell.Style.BackColor = Color.Wheat;
cell.ValueType = typeof(string);
cell.Value = "Door";
column.CellTemplate = cell;
//add to the grid.
dataGridViewFields.Columns.Insert(ii, column);
dataGridViewFields.Columns[ii].DataPropertyName = dpName;
//dataGridViewFields.EditMode = DataGridViewEditMode.EditProgrammatically;
}
I think you would be interested in the DisplayStyle of the ComboBox Column
Set DisplayStyle to Nothing. This will make the ComboBox appear only when you try to Edit the cell

Categories

Resources