Datagridview C#

Setup

Add column: dgv.Columns.Add("ID", "ID");
Set width column: dgv.Columns[0].Width = 40;
Select complete rows: dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
Hide rowheaders (first column, to select a row): dgv.RowHeadersVisible = false;
Make read-only: dgv.ReadOnly = true;
Set standard height: dgv.RowTemplate.Height = 18; //Standard height = 22
Set properties AllowUserToAddRows and AllowUserToDeleteRows to false. If not, a blanc line will always be shown to add rows.
User can not change height of a row: dgv.AllowUserToResizeRows = false

Make a child grid, showing details of a master grid

In the properties of the bindingsource of the child grid:
Set DataSource to the bindingsource of the master grid.
Set DataMember to the entity you want to be shown in the child grid.

Remark: the members of the datasource of the bindingsource, have to be properties (with get; set; ) If not, they will not be shown as possible columns.

Connecting to a datasource

Manual

Set grid

dgv.Columns.Add("datasourcename", "columnheadername");
dgv.Columns[0].Width = 40;
dgv.Columns[0].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;

Fill grid
dgv.Rows.Clear();
List<Test> data = Test.GetAll();
foreach (Test line in data)
{
  dgv.Rows.Add(line.field1);
}

Advantage: you can completely form the grid as you want, with different colors per row …
Disadvantage: you don't have all the elements later anymore, for instance when the user clicks in a row. You get include the id of the element in a hidden column, get this id, and get the element from the database. The problem is that the data in the database may already have been changed.
Conclusion: avoid this method, unless there is a good reason: impossible to have the data in one object, use of different colors depending on values …

Link the datasource to a collection

Set grid: manual (idem above)
Fill grid:
dgv.DataSource = Test.GetAll()
Get the selected item with: Test mTest = (Test)dgv.CurrentRow.DataBoundItem;
Problem: the grid doesn't use the manual column settings and adds the fields of the DataSource as columns, so you can only use this if you want to show all fields of the object

Link the datasource to a collection, the columns to a bindingsource.

First link the datasource to the bindingsource. Set the columns as desired. You have to object in the Data Sources first.
In code, link the datasource to a collection.
Remark: You have to make the BindingSource and the Data Source anyway, so you can as well use the last solution.

Link the datasource to a bindingsource

Preferred solution.
You can use here dgv_SelectionChanged or BindingSource_CurrentChanged.
BindingSource.Current gives you the selected item.
If you need elements from a linked table, you can select this in the Data part of the column. Probably you'll have to make a new Binding Source / Data Source for this.

Details part

You can link the BindingSource also to discrete controls (details part). The problem is that if you edit the data in this discrete controls, the changes go immediately to the grid, and there is no undo, refresh or whatever.
Therefore it is better to use a second BindingSource. Set the datasource of this second bindingsource to the Current of the bindingsource of the grid. When you add a new element, set the datasource of the secondary BindingSource to new ObjectOfPrimaryBindingSource().

Data using datagridview

Add row (last position)

Insert row: dgv.Rows.Add(test.ID);

Insert row (random position)

DataGridViewRow row = new DataGridViewRow();  // or: DataGridViewRow row = dgv.Rows[dgv.CurrentRow.Index]
row.CreateCells(dgvStatus);
row.Cells[0].Value = status;  // or: row.SetValues(...)
dgvStatus.Rows.Insert(0, row);

Remove row

dataGridView.Rows.RemoveAt(x);

Data using bindingsource

Add row (last position)

bs.Add(Product);
bs.MoveLast;

Change row

ProductDL.Update(product)
// Not necessary if product references to the object in the binding source:
bsProduct.Item(bsProduct.Position) = product

Selected row

bs.Current

A row is affected by an external cause

CType(bsInvoice.Current, InvoiceView).Recalculate()  // This should update the internal object shown in the grid.
dgvFactuur.InvalidateRow(dgvFactuur.CurrentRow.Index)

Changing layout depending on contents

Private Sub dgvLijstProduct_CellFormatting(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles dgvLijstProduct.CellFormatting
  If CType(bsProducts.Item(e.RowIndex), Product).passief Then
    e.CellStyle.ForeColor = Color.DarkGray
  End If
End Sub

Events

CellClick: is fired when the user clicks in the cell.
CellContectClick: is fired when the user clicks in the cell and on the context.
Both don't react when moved with arrow keys.
Use SelectionChanged instead. See also snippets.

private void dgv_CellClick(object sender, DataGridViewCellEventArgs e)
{
  textBoxt1.Text = (string)dgv[e.ColIndex, e.RowIndex].Value;
}

Sorting

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License