I use dataGridView.DataSource = myList; to populate a dataGridView.
I use the following code to hide a class member:
[System.ComponentModel.Browsable(false)]
public string SomeInformation { get; set; }
But, is there also a way to say that a class member should be represented as a ComboBox?
If not, is there any way that I can change it with code? I tried the following:
DataGridViewComboBoxCell comboBoxCell = new DataGridViewComboBoxCell();
comboBoxCell.DataSource = State.Instance.ProductCategories.ToList();
dataGridView[2, 0] = comboBoxCell;
dataGridView[2, 0].Value = State.Instance.ProductCategories.ToList()[0];
The value of the field will be fine, but there is still no ComboBox.
Any help?
Edit:
I now use the following code:
dataGridView.DataSource = State.Instance.Products;
dataGridView.DataError += delegate(object o, DataGridViewDataErrorEventArgs args)
{
MessageBox.Show(args.Exception.Message);
};
DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
col.DataPropertyName = "Categorie";
col.Name = "Categorie";
col.Visible = true;
col.HeaderText = "Categorie";
col.DataSource = State.Instance.ProductCategories.ToList();
col.DisplayMember = "Name";
col.DisplayIndex = 1;
dataGridView.Columns.Add(col);
dataGridView.CellEndEdit += delegate(object o, DataGridViewCellEventArgs args)
{
State.Instance.Save();
// If I check the value here, it is a string.
};
But when I save the state, the value is not being changed. Can that be because I added the column myself and it does not know where to save it?
[System.ComponentModel.Browsable(false)]
public ProductCategory Categorie { get; set; }
And in the CellEndEdit event, I only get the string back, but not the whole object.
You can set DataGridView.AutoGenerateColumns=false and then add all columns in code, or auto generate columns and then add your custom column (change DisplayIndex to set its position):
DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
col.DataPropertyName = "SomeInformation";
col.Name = "colSomeInformation";
col.Visible = true;
col.HeaderText = "Some Information"
col.DataSource = State.Instance.ProductCategories.ToList();
// set other column properties here...
dataGridView.Columns.Add(col);
I once had to autogenerate datagridview's columns of different types based on external settings, and I used xml config files for this. As far as I know, there's no built-in solution to do it.
EDIT:
How the ValueMember works:
class ProductCategory
{
public int ID {get;set;}
public string Name {get;set;}
}
class Product
{
public int ID {get;set;}
public string Name {get;set;}
public int CategoryID {get;set;}
}
// Example data binding:
BindingList<Products> bl = new BindingList<Products>(State.Instance.Products.ToList());
BindingSource bs = new BindingSource();
bs.DataSource=bl;
dataGridView.DataSource = bs;
DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
col.DataSource = State.Instance.Categories.ToList();
col.DataPropertyName = "CategoryID";
col.DisplayMember= "Name"; // name of category
col.ValueMember ="ID"; // id of category
I am pretty sure that that is not possible.
Related
How can you set default value for combobox provided you get the value from table in database. I am thinking comparing the value with column [2]/destinationColumn to see which value in the table should be selected as default. This is my code so far which is wrong. Suggestion or an example code will be much appreciated. Thank you in advance guys.
string sqlLookupColumn = "SELECT LookUpColumnID, SOURCE_NAME FROM TB_LOOKUP_COLUMN ORDER BY SOURCE_NAME ASC";
DataSet dsColumn = databaseManager.GetData(sqlLookupColumn);
DataGridViewComboBoxColumn dgvCboColumn = new DataGridViewComboBoxColumn();
dgvCboColumn.Name = "DESTINATION_NAME";
dataGridView1.Columns.Add(dgvCboColumn);
foreach (DataGridViewRow row in dataGridView1.Rows)
{
DataGridViewComboBoxCell cboDestinationColumns = (DataGridViewComboBoxCell)(row.Cells[3]);
cboDestinationColumns.DataSource = dsColumn.Tables[0];
string destinationColumn = row.Cells[2].Value.ToString();
cboDestinationColumns.DisplayMember = "SOURCE_NAME";
cboDestinationColumns.ValueMember = "LookUpColumnID";
if (destinationColumn == cboDestinationColumns.DisplayMember)
{
cboDestinationColumns.Selected = true;
}
}
Things that i can see wrong
1- Your loop on the GridView wont work, do the loop on the Dataset instead of the Gridview...
2- You are comparing destinationColumn with cboDestinationColumns.DisplayMember which = "SOURCE_NAME" and you want If destinationColumn = "InvoiceNo"
3- Add the to the combo items using for loop and .add method, and do your if statement their.
To add the items:
1st add this class
public class ComboboxItem
{
public string Text { get; set; }
public object Value { get; set; }
public override string ToString()
{
return Text;
}
}
Then loop on the Dataset
for(int i=0;i<ds.Tables[0].Rows.Count;i++)
{
DataRow dr = ds.Tables[0].Rows[i];
ComboboxItem tmp= new ComboboxItem();
tmp.Text = dr["SOURCE_NAME"];
tmp.Value = dr["LookUpColumnID"];
cb.Items.Add(tmp);
if(dr["InvoiceNo"].ToString() =="")//Your condition here to set selected
cb.SelectedIndex = i;
}
I'm new to C# and .NET
I need to display the matching name of a value in a databound DatagridViewComboBox, but I can't figure out how to do that.
I have the following code:
bs = new BindingSource();
bs.DataSource = typeof(CR);
dataGridView1.AutoGenerateColumns = false;
Column1.Width = 400;
Column1.DataPropertyName = "CR_NAME";
Column2.DataPropertyName = "CR_STATE_S";
Column2.ValueMember = "CR_STATE_S";
Column2.DisplayMember = "GetStateName";
Column2.Items.Add("0"); // how to set the matching value here?
Column2.Items.Add("1");
Column2.Items.Add("2");
dataGridView1.DataSource = bs;
GetStateName is a property of the CR Class that returns the matching name of the CR state. I need to display the state name in the combo box. How to do that? Thanks.
If you want to display something different from the values the cells shall contain, then you can't simply load one thing into the Items of the ComboBoxCells.
Instead you need a DataSource that has at least different fields for the two things you want to use:
A field for the visible representation of the data, called DisplayMember
And a field for the actual data values, called ValueMember
These fields can sit in a DataTable but you can also use any other collection with suitable properties.
Lets create a very simple class and have a List of that class:
class itemClass
{
public string display { get; set;}
public string value { get; set; }
public itemClass(string d, string v)
{ display = d; value = v;}
}
List<itemClass> myItems = new List<itemClass>();
private void loadButton_Click(object sender, EventArgs e)
{
// load the list with all values:
myItems.Add(new itemClass("zero", "0"));
myItems.Add(new itemClass("one", "1"));
myItems.Add(new itemClass("two", "2"));
myItems.Add(new itemClass("three", "3"));
myItems.Add(new itemClass("four", "4"));
myItems.Add(new itemClass("five", "5"));
myItems.Add(new itemClass("six", "6"));
// prepare the DataGridView 'DGV':
DGV.Columns.Clear();
DataGridViewComboBoxCell cCell = new DataGridViewComboBoxCell();
DataGridViewComboBoxColumn cCol = new DataGridViewComboBoxColumn();
DGV.Columns.Add(cCol);
cCol.DisplayMember = "display";
cCol.ValueMember = "value";
cCol.DataSource = myItems;
cCol.ValueType = typeof(string);
// add a few rows, for testing:
DGV.Rows.Add(7);
for (int i = 0; i < DGV.Rows.Count;
i++) DGV.Rows[i].Cells[0].Value = i + "";
}
In the example I load the Items manually. Usually you will want to pull the values from the database or some other source. You can do that either by loading the datasource list as above or you can have a lookup table either independently or in in a DataSet.
If all cells need to have individual lookup values you need to load them separately and not use the column but each of the cells cast to DataGridViewComboBoxCell.
Given the following classes:
public class Shirt
{
public string Description { get; set; }
public List<Color> ColorOptions { get; set; }
public int SelectedColorId { get; set; }
}
public class Color
{
public int Id { get; set; }
public string Label { get; set; }
}
Why can't I get the combobox to show up in the DataGridView using the following code?
List<Shirt> foundShirts = _dbShirtRepo.GetShirts();
var nameColumn = new DataGridViewTextBoxColumn();
nameColumn.DataPropertyName = "Description";
nameColumn.HeaderText = "Description";
var colorSelectColumn = new DataGridViewComboBoxColumn();
colorSelectColumn.DataPropertyName = "ColorOptions";
colorSelectColumn.DisplayMember = "Label";
colorSelectColumn.ValueMember = "Id";
dataGridView1.Columns.Add(nameColumn);
dataGridView1.Columns.Add(colorSelectColumn);
dataGridView1.DataSource = foundShirts;
Try something like this:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 1)
{
DataGridViewComboBoxCell combo = this.dataGridView1[1, e.RowIndex] as DataGridViewComboBoxCell;
combo.DataSource = ((Shirt)dataGridView1.Rows[e.RowIndex].DataBoundItem).ColorOptions;
}
}
As you can see, you have to provide DataSource per request because you can only have one at a time. There's no way to pre-set different data sources for each combo in each row.
You can improve the above solution but the concept is the same:
User clicks, hovers or otherwise "activates" the cell
Set up the DataSource of the column's combo before user has a chance to open it
This way user is not aware of any shenanigans going on and you can offer different choice for every individual row.
Note: I'm not 100% sure of how DataGridViewComboBoxCell operates, it's entirely possible that it caches and persists its data sources but experiment a bit before relying on it.
You have not set the DataSource property for the DataGridViewComboBoxColumn. There are different ways to solve your problem.
Set the DataSource of the DataGridViewComboBoxColumn to foundShirts.ColorOptions. With this you get to see only colors available in the foundShirts list.
var colorSelectColumn = new DataGridViewComboBoxColumn();
colorSelectColumn.DataPropertyName = "ColorOptions";
colorSelectColumn.DisplayMember = "Label";
colorSelectColumn.ValueMember = "Id";
colorSelectColumn.DataSource = foundShirts.ColorOptions;
If you want to see all the possible colors you could have, prepare a separate list of all possible colors and set it as the DataGridViewComboBoxColumn DataSource.
List<Color> allAvailableColorOptions = new List<Color>();
// add all the possible colors to this list.
var colorSelectColumn = new DataGridViewComboBoxColumn();
colorSelectColumn.DataPropertyName = "ColorOptions";
colorSelectColumn.DisplayMember = "Label";
colorSelectColumn.ValueMember = "Id";
colorSelectColumn.DataSource = allAvailableColorOptions;
Could anyone give a snippet of sample code for manually creating columns for DataGridView? I need to create columns with custom names and also manually select what values to show in the column cells. I have the DataGridView bound to a Collection<>
private void initialiseDataGridView(Part part, string batchNumber){
dataCollection = new DataCollection(part.name, batchNumber);
dataCollectionSource = new BindingSource(dataCollection, null);
serialConDataGrid.DataSource = dataCollectionSource;
serialConDataGrid.AutoGenerateColumns = false;
// Add columns
DataGridViewCheckBoxColumn selectedCol = new DataGridViewCheckBoxColumn(false);
selectedCol.HeaderText = "Selected";
DataGridViewColumn runNumberCol = new DataGridViewColumn();
runNumberCol.HeaderText = "Run Number";
serialConDataGrid.Columns.Clear();
serialConDataGrid.Columns.Add(selectedCol);
serialConDataGrid.Columns.Add(runNumberCol);
// How can I specify which values to populate into the column cells here?
}
This msdn sample seems to be empty.
Here is a simple example on how to do it.
Here is the class of objects you want to display in the DataGridView. The things you want to display needs to be properties:
public class Fruit
{
public string Name { get; set; }
public Color Color { get; set; }
public Fruit(string name, Color color)
{
Name = name;
Color = color;
}
}
And here is the code for binding this data to the DataGridView. You need to link the name of the property to the dataGridViewColumn.DataPropertyName property.
// The list of objects
List<Fruit> fruit = new List<Fruit>( )
{new Fruit("Apple",Color.Red),
new Fruit("Orange",Color.Orange),
new Fruit("Pear",Color.Green)};
BindingSource source = new BindingSource(fruit, null);
dataGridView1.AutoGenerateColumns = false;
DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
column.HeaderText = "Name Of Fruit";
column.DataPropertyName = "Name"; // Name of the property in Fruit
dataGridView1.Columns.Add(column);
DataGridViewTextBoxColumn colorColumn = new DataGridViewTextBoxColumn();
colorColumn.HeaderText = "Color";
colorColumn.DataPropertyName = "Color"; // Name of the property in Fruit
dataGridView1.Columns.Add(colorColumn);
dataGridView1.DataSource = source;
You can do that:
Programatically-add-new-column-to-datagridview
The columns need "DataPropertyName" Property to bind to field name.
DataGridViewTextBoxColumn
Here is my code:
DataSet data = new DataSet();
data.ReadXml("data.xml");
DataGridView grid = new DataGridView();
var genreCboBoxItems = data.Tables[0].AsEnumerable().Select(genre => genre.Field<string>("genre")).Distinct().ToArray();
// TODO: Make is so the 'genre' column in grid is a combo box?
grid.DataSource = data.Tables[0];
grid.Dock = DockStyle.Fill;
this.Controls.Add(grid);
*edit: genreCboBoxItems
Try this: (not tested)
var column = new DataGridViewComboBoxColumn();
column.DataSource = data.Tables[0].AsEnumerable().
Select(genre => new { genre = genre.Field<string>("genre") }).Distinct();
column.DataPropertyName = "genre";
column.DisplayMember = "genre";
column.ValueMember = "genre";
grid.DataSource = data.Tables[0];
// Instead of the below line, You could use grid.Columns["genre"].Visible = false;
grid.Columns.Remove("genre");
grid.Columns.Add(column);
This might help you cast DataGridViewColumn to DataGridViewComboBox.
First create DataGridViewComboBoxColumn using designer with proper name. Then say you have a list of String list and other string values to bind to that datagridview then use this code:
Below code will bind a list to two DataGridViewTextBoxCell and a DataGridViewComboBoxCell. Note AllCriterias is a list with two string values and a list of string. DGVEligibilityCriteria is the grid name.
for (int i = 0; i < AllCriterias.Count; i++)
{
DataGridViewTextBoxCell Cmb1 = (DataGridViewTextBoxCell)DGVEligibilityCriteria.Rows[i].Cells[0];
Cmb1.Value = AllCriterias[i].Name;
DataGridViewTextBoxCell Cmb2 = (DataGridViewTextBoxCell)DGVEligibilityCriteria.Rows[i].Cells[1];
Cmb2.Value = AllCriterias[i].Type;
DataGridViewComboBoxCell Cmb = (DataGridViewComboBoxCell)DGVEligibilityCriteria.Rows[i].Cells[2];
foreach (var filtervalue in AllCriterias[i].FilterValues)
{
Cmb.Items.Add(filtervalue);
}
}
Need to display the fist index as default by setting selectindex property.
Use this code : Here "filterValues" is the name of the DataGridViewComboBoxCell which u created in the datagridview designer.
foreach (DataGridViewRow row in DGVEligibilityCriteria.Rows)
{
row.Cells["filterValues"].Value = (row.Cells["filterValues"] as DataGridViewComboBoxCell).Items[0];
}