I want a Delete button at the end of each row of DataGridView and by clicking that I want to remove the desired row from the binding list which is data source of my grid.
But I can't seem to do it I have created a button object in product class and instantiated it with the unique id to remove that object from list. but button is not showing in the row.
There are TextBoxes in the form and users can enter text, and when they press Add button, a new object of product is instantiated with the provided fields and then it is added to the BindingList.
Finally this list is bound to the DataGridView and details are shown in the grid. (I have done this part).
and at last by clicking save button the list is saved in the DB.
public class Product{
public string Brand { get; set; }
public int ProductPrice { get; set; }
public int Quantity { get; set; }
public product(string brand,int productPrice, int quantity){
this.Brand = brand;
this.ProductPrice = productPrice;
this.Quantity = quantity;
}
}
public partial class MainForm: Form{
.....
BindingList<Product> lProd = new BindingList<Product>();
private void btnAddProduct_Click(object sender, EventArgs e){
string Brand = txtProBrand.Text;
int Price = Convert.ToInt32(txtPrice.Text);
int Quantity = Convert.ToInt32(txtQuantity.Text);
Product pro = new Product(Brand, Price, Quantity);
lProd.Add(pro);
dataGridView1.DataSource = null;
dataGridView1.DataSource = lProd;
}
.....
}
To show a button on DataGridView rows, you should add a DataGridViewButtonColumn to columns of your grid. Here is some common tasks which you should know when using button column:
Add Button Column to DataGridView
Show Image on Button
Set Text of Button
Handle Click Event of Button
Add Button Column to DataGridView
To show a button on each row of your grid, you can add a DataGridViewButtonColumn to columns of your grid programmatically or using designer:
var deleteButton=new DataGridViewButtonColumn();
deleteButton.Name="dataGridViewDeleteButton";
deleteButton.HeaderText="Delete";
deleteButton.Text="Delete";
deleteButton.UseColumnTextForButtonValue=true;
this.dataGridView1.Columns.Add(deleteButton);
Show Image on Button
If you prefer to draw image on button, you should have an image in a resource and then handle CellPainting event of your grid:
void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex == dataGridView1.NewRowIndex || e.RowIndex < 0)
return;
if (e.ColumnIndex == dataGridView1.Columns["dataGridViewDeleteButton"].Index)
{
var image = Properties.Resources.DeleteImage; //An image
e.Paint(e.CellBounds, DataGridViewPaintParts.All);
var x = e.CellBounds.Left + (e.CellBounds.Width - image.Width) / 2;
var y = e.CellBounds.Top + (e.CellBounds.Height - image.Height) / 2;
e.Graphics.DrawImage(image, new Point(x, y));
e.Handled = true;
}
}
Set Text of Button
You can use either of these options:
You can set Text property of your DataGridViewButtonColumn and also set its UseColumnTextForButtonValue to true, this way the text will display on each cells of that column.
deleteButton.Text="Delete";
deleteButton.UseColumnTextForButtonValue=true;
Also you can use Value property of cell:
this.dataGridView1.Rows[1].Cells[0].Value = "Some Text";
Also as another option, you can handle CellFormatting event of your grid. This way may be useful when you want to set different texts for buttons.
void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
//If this is header row or new row, do nothing
if (e.RowIndex < 0 || e.RowIndex == this.dataGridView1.NewRowIndex)
return;
//If formatting your desired column, set the value
if (e.ColumnIndex=this.dataGridView1.Columns["dataGridViewDeleteButton"].Index)
{
e.Value = "Delete";
}
}
Handle Click Event of Button
To hanlde clicks on button, you can handle CellClick or CellContentClick event of your grid. Both events fires by click and by pressing Space key.
void dataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
{
//if click is on new row or header row
if( e.RowIndex == dataGridView1.NewRowIndex || e.RowIndex < 0)
return;
//Check if click is on specific column
if( e.ColumnIndex == dataGridView1.Columns["dataGridViewDeleteButton"].Index)
{
//Put some logic here, for example to remove row from your binding list.
//yourBindingList.RemoveAt(e.RowIndex);
// Or
// var data = (Product)dataGridView1.Rows[e.RowIndex].DataBoundItem;
// do something
}
}
Get data of the record on Click event
You have e.RowIndex, then you can get the data behind the row:
var data = (Product)dataGridView1.Rows[e.RowIndex].DataBoundItem;
// then you can get data.Id, data.Name, data.Price, ...
You need to cast it to the data type of the recore, for example let's say Product.
If the data binding has been setup to use a DataTable, the the type to cast is DataRowView.
You can also use dataGridView1.Rows[e.RowIndex].Cells[some cell index].Value to get value of a specific cell, however DataBoundItem makes more sense.
Note
As mentioned by Ivan in comments, when you use BindingList you don't need to set datasource of grid to null and back to binding list with every change. The BindingList itself reflects changes to your DataGridView.
Related
I have created more than 5 GRID for which there are a few column that are empty/zero. These are numbered as example 1,2,3...
I have already implemented that I can select and deselect single cells for this columns.
Now my question is (and I am still very inexperienced with Infragistics)
How do I get the Name Property of my grid just by clicking on it?
Some parameters I could read out like the cells.index or the rows.index, but I want to know for another method the exact Name Property in which just the cell was clicked.
Via the event handler I let all my grids into the cells click method
private void GRD_LIST_Grid_ClickCell(object sender, Infragistics.Win.UltraWinGrid.ClickCellEventArgs e)
{
if (e.Cell.Column.ToString().Contains("BAHN") && e.Cell.Tag == "1") //1-5 Column have the name "BAHN", the Tag is for an flag if the cell is clicked before
{
e.Cell.Selected = false;
e.Cell.Tag = null;
SetPrio(e.Cell.Row.Index, e.Cell.Column.Index);
}
else if (e.Cell.Column.ToString().Contains("BAHN") && e.Cell.Tag == null)
{
SetPrio(e.Cell.Row.Index, e.Cell.Column.Index);
e.Cell.Tag = "1";
}
//when the cell is click show the cell in green
if (e.Cell.Tag == "1")
{
e.Cell.Row.Cells[e.Cell.Column.ToString()].Appearance.BackColor = System.Drawing.Color.Green;
}
else if (e.Cell.Tag == null)
{
e.Cell.Row.Cells[e.Cell.Column.ToString()].Appearance.BackColor = System.Drawing.Color.FromArgb(234,244,243);
}
ClearSelectedRow(); //a Method where i set all grids in an array and clear all rows because i dont know which grid i am
}
When the ClickCell event occurs the first parameter of the event handler is sender and in this case it's the Infragistics.Win.UltraWinGrid.UltraGrid source. Therefore, it is possible to get the grid name like in code below:
private void GRD_LIST_Grid_ClickCell(object sender, Infragistics.Win.UltraWinGrid.ClickCellEventArgs e)
{
if (sender is Infragistics.Win.UltraWinGrid.UltraGrid ugrid)
{
System.Diagnostics.Debug.WriteLine($"The ClickCell event is raised by '{ugrid.Name}'");
}
}
I am trying to make a datagridview in which there exists a combobox column, and this column is binded a list of options. My logic is that, if the user selects the wrong option, the program could detect and deselect this wrong option(which means comboboxCell.value = null).
The psuedo code for this logic is as follows:
//use CurrentCellDirtyStateChanged and CellValueChanged as event listeners
this.DGV.CurrentCellDirtyStateChanged += DGV_CurrentCellDirtyStateChanged;
this.DGV.CellValueChanged += DGV_CellValueChanged;
//CurrentCellDirtyStateChanged event
private void DGV_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (DGV.IsCurrentCellDirty)
{
DGV.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
//CellValueChanged event
private void DGV_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (!CheckingCorrect(DGV.CurrentCell))
{
// set selected value null
DGV.CurrentCell.Value = null
}
}
However, after the code sets currentcell value to null, the datagridview cell still kept the selected value shown.
I also tried may other ways like DGV.ClearSelection(), but none of these works.
There are two things that will make working with the DataGridViewComboBoxColumn/Cell easier...
Make a Class specifically for the combo box column
Use the proper event to help in casting the DataGridViewComboBoxCell to a
regular ComboBox.
In this example I made a simple Class called ComboValues that has two properties for the column ValueMember and DisplayMember. In this example the ValueMember is an int, however you could leave it out or use some other type that fits your needs. This class will simplify things as we will have the properties for both the ValueMember and DisplayMember for the combo box column.
This ComboValues Class may look something like…
public class ComboValues {
public int Value { get; set; }
public string Display { get; set; }
}
Then a method to get a List<ComboValues> from the DB that we will use as a DataSource for the combo box column.
private List<ComboValues> GetComboValues() {
List<ComboValues> items = new List<ComboValues>();
items.Add(new ComboValues { Value = 0, Display = null });
items.Add(new ComboValues { Value = 1, Display = "Option 1" });
items.Add(new ComboValues { Value = 2, Display = "Option 2" });
items.Add(new ComboValues { Value = 3, Display = "Option 3" });
items.Add(new ComboValues { Value = 4, Display = "Option 4" });
return items;
}
And setting up the combo box column for the grid…
private DataGridViewComboBoxColumn GetComboCol() {
DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
col.HeaderText = "Combo Items";
col.ValueMember = "Value";
col.DisplayMember = "Display";
col.DataSource = GetComboValues();
return col;
}
We will call the above method in the forms Load event to add the column to the Grid…
private void Form1_Load(object sender, EventArgs e) {
DGV.Columns.Add(GetComboCol());
}
Next, we want to set up the edited DataGridViewComboBoxCell to act like a REGULAR ComboBox. We can do this using the grids EditingControlShowing event. This event will fire when the user clicks into a cell and in this case if the user clicks into a combo box cell, then we want to cast that cell to a globally defined ComboBox. So, we will need a global ComboBox variable called something like… EditedComboBox.
ComboBox EditedComboBox = null;
Is what we will do is that when the grids EditingControlShowing event fires and we check to see if it is the combo box cell, then we simply cast that cell to our global EditedComboBox and wire up its SelectedIndexChanged event. Then we can capture “when” the user “changes” a value in the combo box cell. The EditingControlShowing event may look something like…
private void DGV_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
if (DGV.CurrentCell.ColumnIndex == 0) {
EditedComboBox = (ComboBox)e.Control;
if (EditedComboBox != null) {
EditedComboBox.SelectedIndexChanged += new EventHandler(ComboBox_SelectedIndexChanged);
}
}
}
Above, column index 0 is the target combo box column. All we need to do is implement and wire up the SelectedIndexChanged event and wait for the user to change the combo box value.
When the user does indeed change the combo boxes value, then our SelectedIndexChanged event will fire and it is in this event where you would “CHECK” if the selected value needs adjustments on some parameters. In this example, the condition is if the user selects “Option 3”, then that is an invalid value and we will set the cells value to null. This event may look something like…
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e) {
//Debug.WriteLine("CB_SelectedIndexChanged");
if (EditedComboBox != null) {
ComboValues cv = (ComboValues)EditedComboBox.SelectedItem;
if (cv != null && !CheckingCorrect(cv.Display)) {
EditedComboBox.SelectedIndexChanged -= new EventHandler(ComboBox_SelectedIndexChanged);
EditedComboBox.SelectedIndex = 0;
EditedComboBox.SelectedIndexChanged += new EventHandler(ComboBox_SelectedIndexChanged);//DGV.CurrentCell.Value = 0;
}
}
}
In this event, we grab (cast) the combo boxes SelectedItem to a ComboValues object. With it we can easily check what value is selected and in turn set its value to null if needed. Note “item” 0 in our List<ComboValues> is the null value, so we set the combo boxes SelectedIndex to zero (0) to make the grid display a null value.
Also, since we are “changing” the combo boxes Index, we do NOT want this event to re-fire.
Lastly, we need one more event to wire up to TURN OFF the SelectedIndex changed event to prevent it from firing more than we want. In this case we will wire up the grids CellLeave event. In that event, the user is leaving the cell and if the EditedComboBox is not null... then we know we need to un-wire the event. It may look something like…
private void DGV_CellLeave(object sender, DataGridViewCellEventArgs e) {
if (EditedComboBox != null) {
EditedComboBox.SelectedIndexChanged -= new EventHandler(ComboBox_SelectedIndexChanged);
EditedComboBox = null;
}
}
I altered the checking code to check for a string and not necessarily a cell. The condition checker code…
private bool CheckingCorrect(string cellValue) {
if (cellValue != null && cellValue == "Option 3") {
return false;
}
else {
return true;
}
}
I hope this helps and makes sense. If you have questions, then feel free to ask.
I created a user control which has datagridview. Then I added row and column dynamically from textfile in datagridview.
My problem is I need column which has buttons in each row. In first row, the text of button is 'Test1' and in second row 'Test2' not the same text.
After searched on google I tried this code
var testButton = new DataGridViewButtonColumn();
testButton.Name = "Test";
testButton.HeaderText = "Test";
testButton.UseColumnTextForButtonValue = true;
testButton.Text = "Test1";
this.dataGridView1.Columns.Add(testButton);
But it gives me both button text as 'Test1'.
Assuming you are in Windows Forms, you need to add a DataGridViewButtonColumn to your DataGridView - Not directly to the DataTable.
This should occur somewhere after you bind the DataTable to the DataGridView.
Something like this should work:
DataGridViewButtonColumn uninstallButtonColumn = new DataGridViewButtonColumn();
uninstallButtonColumn.Name = "uninstall_column";
uninstallButtonColumn.Text = "Uninstall";
int columnIndex = 2;
if (dataGridViewSoftware.Columns["uninstall_column"] == null)
{
dataGridViewSoftware.Columns.Insert(columnIndex, uninstallButtonColumn);
}
Of course you will have to handle the CellClick event of the grid to do anything with the button.
Add this somewhere in your DataGridView Initialization code
dataGridViewSoftware.CellClick += dataGridViewSoftware_CellClick;
Then create the handler:
private void dataGridViewSoftware_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == dataGridViewSoftware.Columns["uninstall_column"].Index)
{
//Do something with your button.
}
}
//Change the Button text property on a data-bound event
protected void YourDataGridViewId_RowDataBound(object sender, GridViewRowEventArgs e)
{
// finding the button control..`enter code here`.
if (e.Row.RowType == DataControlRowType.DataRow)
{
Button YourbtnVariable = (Button)e.Row.FindControl("YourbuttonID");
YourbtnVariable.Text = "Text"+e.Row.RowIndex+1;
//e.Row.RowIndex+1 will give u index of row every time incremented with 1
}
}
I Have a datagridview that gets data from database and shows to the user,I also have three textboxes through which user can enter the value into the datagrid view if I select an already existing row in the datgrid and then enter value by text boxes it makes the changes and when I push change button changes are made successfully in both db and the datagridview
but if I select an empty row in the datagrid view and try to enter the values I cannot new row is not added to the datagrid view although allow user to add new row is set to true.
private void txtName_TextChanged(object sender, EventArgs e)
{
if (dataGridView1.SelectedRows.Count == 1)
{
dataGridView1.SelectedRows[0].Cells["Name"].Value = txtName.Text;
}
}
private void txtRelation_TextChanged(object sender, EventArgs e)
{
if (dataGridView1.SelectedRows.Count == 1)
{
dataGridView1.SelectedRows[0].Cells["Relation"].Value = txtRelation.Text;
}
}
private void txtID_TextChanged(object sender, EventArgs e)
{
if (dataGridView1.SelectedRows.Count == 1)
{
dataGridView1.SelectedRows[0].Cells["ID"].Value = txtID.Text;
}
}
Check if your gridview is readonly. If Readonly is true then set it to false to enable user add new row. Another reason might be the "EditMode" property of DataGridView. It should not be "Edit Programatically" if you want to allow user to add new row
You have to double click a row to actually create a new row. However, if you do not want the stress of double clicking, you could make the row select event to perform a click on the row.
I'm trying to update this DataGridView object such that if a value == "bob" there will be a button in a column next to its name, otherwise I don't want any button to appear.
DataGridViewTextBoxColumn valueColumn = new DataGridViewTextBoxColumn();
DataGridViewButtonColumn buttonColumn = new DataGridViewButtonColumn();
buttonColumn.ReadOnly = true;
buttonColumn.Visible = false;
this.dgv.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
valueColumn,
buttonColumn,
});
//elsewhere...
if(value == "bob")
{
Button button = new Button()
{
Text = "null",
};
index = dgv.Rows.Add(value, button);
DataGridViewButtonCell buttonCell = dgv.Rows[index].Cells[2] as DataGridViewButtonCell;
buttonCell.Visible = true;
}
else
{
dgv.Rows.Add(value);
}
But, since I can't set Visible on a cell, this doesn't work. Is there a way to add a button to only the rows were Value == "bob"?
Here is a neat little hack that I've used before to accomplish this:
Instead of using a DataGridViewButtonColumn, use the DataGridViewTextBoxColumn and add a DataGridViewButtonCell where appropriate.
e.g.
private void button1_Click(object sender, EventArgs e)
{
// Iterate through each of the rows.
for (int i = 0; i < dgv.RowCount - 1; i++)
{
if (dgv.Rows[i].Cells[0].Value.ToString() == "bob")
{
// Here is the trick.
var btnCell = new DataGridViewButtonCell();
dgv.Rows[i].Cells[1] = btnCell;
}
}
}
In the example above, I have two DataGridViewTextBoxColumns and iterate through each of the rows on a button click event. I check the first column to see if it contains "bob" and if it does, I add a button in the column next to it. You can use this trick however you want (i.e. button clicks, RowsAdded event, CellEndEdit event, etc.). Experiment in different ways. Hope this helps someone!
There are two possibilities here, one ugly and one from MSDN.
The Ugly: Add a button to your DGV at runtime
Do the following:
- Add an unbound DataGridViewTextBoxColumn to your DGV. Note it's index value in your DGV; this is where you'll put your button.
- Use your DGV's CellFormatting event like so:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) {
if (e.ColumnIndex == 0) { // Assumes column 0 has the data that determines if a button should be displayed.
if (e.Value.ToString() == "bob") { // Test if a button should be displayed on row.
// Create a Button and add it to our DGV.
Button cellButton = new Button();
// Do something to identify which row's button was clicked. Here I'm just storing the row index.
cellButton.Tag = e.RowIndex;
cellButton.Text = "Hello bob";
cellButton.Click += new EventHandler(cellButton_Click);
dataGridView1.Controls.Add(cellButton);
// Your ugly button column is shown here as having an index value of 3.
Rectangle cell = this.dataGridView1.GetCellDisplayRectangle(3, e.RowIndex, true);
cellButton.Location = cell.Location;
}
}
}
When a user clicks the button the cellButton_Click event will fire. Here's some test code:
void cellButton_Click(object sender, EventArgs e) {
Console.WriteLine("Hello from row: {0}", ((Button) sender).Tag);
}
As you can see this isn't very refined. I based it on an even uglier sample I found. I'm sure you can modify it to suit your needs.
From MSDN: Roll your own (extend) DataGridViewButtonColumn that conditionally displays a disabled button.
For this option see How to: Disable Buttons in a Button Column in the Windows Forms DataGridView Control
Of course this option doesn't actually remove any buttons, only conditionally disables them. For your application however, this might be better.
You can handle cell painting on cell painting event:
private void dgv_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if(e.RowIndex>=0 && e.ColumnIndex == indexOfButtonColumn && value[e.RowIndex] != "bob")
{
e.Paint(e.ClipBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.ContentForeground & ~DataGridViewPaintParts.ContentBackground);
e.Handled = true;
}
}