Reputation: 5291
In my project I wanted to read data from a file and update the DataGridView to a simple List. I wanted this so that the list can be updated at run time and then upon save wanted the final content of the list to be updated to a file.
In most of the solutions seen on google search I came up with examples of how to use a DatagridView with Database connection used to update the DatagridView. for Insert, Update and Delete operations. Lot of suggestions for my answer included adding INotifyProperty and IBindingList based impelementations which are probably an overkill.
I only aim to post my solution which involves using Datagridview to update a list. The code snippet used here is part of a huge project where updating the data from Datagridview to the List and back was a very big challenge due to initial impelementation with Database, whose dependency needed to be removed.
At the point of posting this question, I have a solution to my problem. To arrive at this problem I have taken bits and pieces of suggestions from various previous questions. I am not looking for suggestions in comments. If anyone wants to show me better way to solve this problem, please post an answer with working code.
Upvotes: 1
Views: 4706
Reputation: 30474
So after reading, you have a sequence of MyData objects. You want to display all MyData objects (or a subsection) in a DataGridView.
Operators may change the displayed values, add some new rows, or delete rows. Some columns may be readonly and can't be changed
After pressing the OK-button, you want to read all MyData objects from the DataGridView and Save them in a file.
Most of your work can be done using the forms designer.
And suddenly: your DataGridView has the columns of the public properties of MyData. And magically, the columns have the correct type. They are able to display the values. Readonly properties have readonly Columns, read-write properties are editable.
To display your data:
void FillDataGridView(IEnumerable<MyData> dataToDisplay)
{
this.bindingSource1.DataSource = new BindingList<MyData>(dataToDisplay.ToList();
}
To read all data after editing
IEnumerable<MyData> ReadDataGridView()
{
return this.bindingSource1.List.Cast<MyData>();
}
This enables the operator to add and delete rows and to edit the values. If you don't want the operator to do this, adjust the DataGridView properties If the displayed values of the columns are not to your liking, edit the column properties (different header text, different display format, different backgroundcolor etc)
Upvotes: 2
Reputation: 5291
Here is an example where I have used the DatagridView to perform Insert Update and Delete on a List (List of Class objects PersonState
).
The DatagridView’s Datasource needs to contain a DataTable, to bridge this gap, I have used a function named ConvertToDatatable()
.
As my starting point I began with a project suggested on another link by Anup Kumar Sharma.
Using the following code:
using System;
using System.Collections.Generic;
using System.Data;
using System.Windows.Forms;
namespace InsertUpdateDelete {
public partial class Form1 : Form {
public class PersonState {
public string Name { get; set; }
public string State { get; set; }
}
public List<PersonState> listOfPersonState;
public Form1() {
InitializeComponent();
listOfPersonState = new List<PersonState>();
}
//Display Data in DataGridView
private void DisplayData() {
DataTable dt = new DataTable();
dt = ConvertToDatatable();
dataGridView1.DataSource = dt;
}
//Clear Data
private void ClearData() {
txt_Name.Text = "";
txt_State.Text = "";
}
public DataTable ConvertToDatatable() {
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("State");
foreach (var item in listOfPersonState) {
var row = dt.NewRow();
row["Name"] = item.Name;
row["State"] = item.State;
dt.Rows.Add(row);
}
return dt;
}
private void AddToList(string text1, string text2) {
listOfPersonState.Add(new PersonState { Name = text1, State = text2 });
}
private void UpdateToList(string text1, string text2) {
int index = dataGridView1.SelectedRows[0].Index;
listOfPersonState[index] = new PersonState { Name = text1, State = text2 };
}
private void DeleteToList() {
int index = dataGridView1.SelectedRows[0].Index;
listOfPersonState.RemoveAt(index);
}
private void btn_Insert_Click(object sender, EventArgs e) {
if (txt_Name.Text != "" && txt_State.Text != "") {
AddToList(txt_Name.Text, txt_State.Text);
//MessageBox.Show("Record Inserted Successfully");
DisplayData();
ClearData();
} else {
MessageBox.Show("Please Provide Details!");
}
}
private void btn_Update_Click(object sender, EventArgs e) {
if (txt_Name.Text != "" && txt_State.Text != "") {
if (dataGridView1.SelectedRows != null && dataGridView1.SelectedRows.Count > 0) {
UpdateToList(txt_Name.Text, txt_State.Text);
//MessageBox.Show("Record Updated Successfully");
DisplayData();
ClearData();
}
} else {
MessageBox.Show("Please Select Record to Update");
}
}
private void btn_Delete_Click(object sender, EventArgs e) {
if (dataGridView1.SelectedRows != null && dataGridView1.SelectedRows.Count > 0) {
DeleteToList();
//MessageBox.Show("Record Deleted Successfully!");
DisplayData();
ClearData();
} else {
MessageBox.Show("Please Select Record to Delete");
}
}
private void dataGridView1_RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
FillInputControls(e.RowIndex);
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) {
FillInputControls(e.RowIndex);
}
private void FillInputControls(int Index) {
if (Index > -1) {
txt_Name.Text = dataGridView1.Rows[Index].Cells[0].Value.ToString();
txt_State.Text = dataGridView1.Rows[Index].Cells[1].Value.ToString();
}
}
}
}
Learnings:
Instead of using:
public class PersonState {
public string Name;
public string State;
}
I have used:
public class PersonState {
public string Name { get; set; }
public string State { get; set; }
}
For some reason, the former does not work when trying to assing values.
I have made the list of objects a class variable so that all functions can access that list directly instead of it being passed around as a parameter.
public List<PersonState> listOfPersonState;
I replaced the logic to Insert, Update and Delete to a DB, to Insert Update and Delete to a List.
private void AddToList(string text1, string text2) {
listOfPersonState.Add(new PersonState { Name = text1, State = text2 });
}
private void UpdateToList(string text1, string text2) {
int index = dataGridView1.SelectedRows[0].Index;
listOfPersonState[index] = new PersonState { Name = text1, State = text2 };
}
private void DeleteToList() {
int index = dataGridView1.SelectedRows[0].Index;
listOfPersonState.RemoveAt(index);
}
Note: I am assigning the Grid directly from the List, so my Grid and my List always have the same index because I am using the Display function to ensure this on Insert, update and delete Button operations.
private void DisplayData() {
DataTable dt = new DataTable();
dt = ConvertToDatatable();
dataGridView1.DataSource = dt;
}
public DataTable ConvertToDatatable() {
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("State");
foreach (var item in listOfPersonState) {
var row = dt.NewRow();
row["Name"] = item.Name;
row["State"] = item.State;
dt.Rows.Add(row);
}
return dt;
}
Upvotes: 0