Why am getting concurrency violation error? - c#

I've MS Access db, datagridview that displays items, two checkbox columns that represents Yes/No columns in the db, and refresh/del buttons.
When I try to delete a row that its checkboxes hasn't been modified, the row delets just fine, also when I modify the checkbox value, press refresh button, then delete, the row deletes fine too.
However when I try to delete a row right after modifying its checkbox value, I get concurrency violation exception error.
When checkbox value changed code:
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].Name == "sales")
{
DataGridViewCheckBoxCell checkCell = (DataGridViewCheckBoxCell)dataGridView1.Rows[e.RowIndex].Cells["sales"];
bool _pSale = (Boolean)checkCell.Value;
string connstring = string.Format(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}", Path.Combine(Directory.GetCurrentDirectory(), "MyDatabase01.accdb"));
OleDbConnection conn = new OleDbConnection(connstring);
conn.Open();
string sqlqry = "UPDATE Items SET pSale = " + _pSale + " WHERE p_Name = '" + this._pName + "'";
OleDbCommand upd = new OleDbCommand(sqlqry, conn);
upd.ExecuteNonQuery();
conn.Close();
//dataGridView1.Invalidate();
}
}
Refresh button code:
public void Refreshdgv()
{
this.categoriesItemsBindingSource.EndEdit();
this.itemsTableAdapter.Fill(myDatabase01DataSet.Items);
this.dataGridView1.Refresh();
}
Delete button code:
private void delBtn_Click(object sender, EventArgs e)
{
try
{
int cnt = dataGridView1.SelectedRows.Count;
for (int i = 0; i < cnt; i++)
{
if (this.dataGridView1.SelectedRows.Count > 0)
{
this.dataGridView1.Rows.RemoveAt(this.dataGridView1.SelectedRows[0].Index);
}
}
this.Validate();
this.categoriesItemsBindingSource.EndEdit();
this.itemsTableAdapter.Update(this.myDatabase01DataSet.Items);
this.myDatabase01DataSet.AcceptChanges();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
To resolve this issue I can call Refreshdgv() method in place of dataGridView1.Invalidate(). But I don't want the dgv refresh for each checkbox click!

The delete command of your DataSet is likely checking the original values. Since you are updating your database manually in the CellValueChanged event, the values in your database won't match the original values in your DataSet. If you modify the CellValueChanged event to use the update command in your DataSet, the values should match up when you call Delete.
Alternatively, you could change your delete command to use a less exclusive where clause (e.g., WHERE KeySegment0 = #keySegment0 AND KeySegment1 = #keySegment1 ...).

Try validiting the data then update it. After that, clear your dataset and fill it up so it would refresh the datagrid every changes you made.

Related

c# (vbs-15) how to fill datagrid and provide links

Sorry guys, but am new to c# and vbs. what am trying to do is to fill datagrid or any equivalent then i need to provide click-able buttons/links to each row.
When user click the button, the app should pass the row-id clicked to new (another) form.
...
p.textquery = "SELECT * FROM members ORDER BY member_id DESC LIMIT 250";
SQLiteConnection m_dbConnection = new SQLiteConnection("Data Source=" + p.dbname() + ";Version=3;");
m_dbConnection.Open();
try
{
SQLiteCommand command = new SQLiteCommand(p.textquery, m_dbConnection);
SQLiteDataReader reader = command.ExecuteReader();
bool rows = reader.HasRows;
if (rows)
{
while (reader.Read())
{
patient_id = reader["patient_id"].ToString();
// Here i need to show results to user but the user should have a button to select the row
}
return;
}
else
{
p.alert("You do not have members in the system");
return;
}
}
catch
{
p.alert("SQL has error - (database error)");
return;
}
...
The problem is how to provide datagrid or any equivalent which has button where user can click to view the record.
Your help is highly appreciated
EDIT
private void dataGridView1_CellContentClick_2(object sender, DataGridViewCellEventArgs e)
{
plugin p = new plugin();
try {
if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex] is DataGridViewButtonCell)
{
//I need the value of the column here member_id is only showing the rowindex and columnindex now i need the value
p.alert(dataGridView1.Rows[e.ColumnIndex].Cells[e.ColumnIndex].ToString());
}
else
{
p.alert(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].ToString() + " on else");
}
}
catch (Exception v)
{
//p.alert("Header clicked ");
}
}
EDIT - ANSWER
dataGridView1.Rows[e.RowIndex].Cells[2].Value.ToString();
where Cells[2] is the targeted cell
Drag and drop a datagridview from the toolbox to the window, Add All the columns in your data table to it using properties--> columns in that add a button column or a link column.
Bind data to grid as below
DataTable dtMembers = new DataTable();
p.textquery = "SELECT * FROM members ORDER BY member_id DESC LIMIT 250";
SQLiteConnection m_dbConnection = new SQLiteConnection("Data Source=" + p.dbname() + ";Version=3;");
try
{
SQLiteDataAdapter da = new SQLiteDataAdapter(p.textquery,m_dbConnection);
m_dbConnection.Open();
da.Fill(dtMembers);
m_dbConnection.Close();
if(dtMembers.Rows.Count > 0)
dgvMembers.DataSource = dtMembers;
else
p.alert("You do not have members in the system");
}
catch
{
p.alert("SQL has error - (database error)");
return;
}
Implement DataGridView cell content click
private void dgvMembers_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if(dgvMembers.Rows[e.RowIndex].Cells[e.ColumnIndex] is DataGridViewButtonCell)
{
//Write your code here
}
}
See below I have text property where I wrote click here, that's where you need to put button name

Winform Datagridview cellclick error - Index was out of range

I've got a simple data grid that lists a bunch of records from a SQLSERVER table. The data grid populates without any issues. I want to click on a row and load the corresponding data into text boxes that I have created next to it. So far so simple.
Here is my code for the cellclick event
private void dataGridVieworderitems_CellClick(object sender, DataGridViewCellEventArgs e)
{
{
//try
//{
//if (dataGridVieworderitems.SelectedRows.Count > 0) // make sure user select at least 1 row
{
string jobId = dataGridVieworderitems.SelectedRows[0].Cells[0].Value + string.Empty;
string standpack = dataGridVieworderitems.SelectedRows[0].Cells[1].Value + string.Empty;
string description = dataGridVieworderitems.SelectedRows[0].Cells[2].Value + string.Empty;
string price = dataGridVieworderitems.SelectedRows[0].Cells[3].Value + string.Empty;
string itemType = dataGridVieworderitems.SelectedRows[0].Cells[4].Value + string.Empty;
string notes = dataGridVieworderitems.SelectedRows[0].Cells[5].Value + string.Empty;
labelidvalue.Text = jobId;
labelstandpackvalue.Text = standpack;
labeldescriptionvalue.Text = description;
textBoxprice.Text = price;
labeltypevalue.Text = itemType;
textBoxnotes.Text = notes;
}
//}
//catch (Exception)
//{
// MessageBox.Show("something went wrong!");
//}
}
}
I have deliberately commented out the If statement and try catch block to generate the error..
I get the following error..
System.ArgumentOutOfRangeException was unhandled HResult=-2146233086
Message=Index was out of range. Must be non-negative and less than the
size of the collection. Parameter name: index ParamName=index ....
...
It's WINFORM and c#.. The datagrid view has the data.. yet it says index is out of range. can some one point me in the right direction please?
This is how I Populate my grid
public DataTable GetStaffCurrentOrderItems()
{
try
{
DataTable dtstaffcurrentorderlist = new DataTable();
string connString = System.Configuration.ConfigurationManager.ConnectionStrings["nav"].ConnectionString;
using (SqlConnection con = new SqlConnection(connString))
{
using (SqlCommand cmd = new SqlCommand("select [ID],standpack as [Item], item_description as [Description], '$'+convert(varchar(5),price) as Price,item_type as [Item Type],notes as [Notes] from tbl_staff_orders_items", con))
{
if (con.State == ConnectionState.Open)
{
con.Close();
}
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
dtstaffcurrentorderlist.Load(reader);
}
con.Close();
}
return dtstaffcurrentorderlist;
}
catch (Exception)
{
return null;
}
}
Make a check within your cellClick event handler for handling the nulls like this
if (dataGridVieworderitems.CurrentCell == null ||
dataGridVieworderitems.CurrentCell.Value == null ||
e.RowIndex == -1) return;
This will sort out your problem as it checks for all the possible nulls while clicking the cell of GridView. An else part will get you the data if there is anything except null.
Hope it helps!
Index was out of range
This means index not found on your datagrid cell.
Kindly check the rows of you datagrid if index exists same with the column too.
Edited:
Ha, got the exact problem source:
The SelectionMode property must be set to FullRowSelect for the SelectedRows property to be populated with selected rows.
Otherwise you can use the following options:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
string jobId = dataGridView1.Rows[e.RowIndex].Cells[0].Value.ToString();
}
or
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
DataGridViewRow selectedRow = dataGridView1.Rows[dataGridView1.SelectedCells[0].RowIndex];
string jobId = selectedRow.Cells[0].Value.ToString();
}

BindingSource not moves to next record with MoveNext() after TableAdapter.Fill

I have this event on a button click below:
private void button4_Click(object sender, EventArgs e)
{
string connectionString2 = "Data Source=LPMSW09000012JD\\SQLEXPRESS;Initial Catalog=Pharmacies;Integrated Security=True";
string query2 = "UPDATE Liguanea_Lane2 SET Progress= '1' where code = '" + comboBox2.Text + "'; ";
using (SqlConnection connection = new SqlConnection(connectionString2))
{
SqlCommand command = new SqlCommand(query2, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
comboBox2.ResetText();
textBox1.Clear();
comboBox2.SelectedIndex = comboBox2.SelectedIndex + 1;
this.liguanea_Lane2TableAdapter.Fill(this.pharmaciesDataSet3.Liguanea_Lane2);
liguaneaLane2BindingSource.MoveNext();
}
The problem is this particular block of code:
this.liguanea_Lane2TableAdapter.Fill(this.pharmaciesDataSet3.Liguanea_Lane2);
liguaneaLane2BindingSource.MoveNext();
Wha it is doing is basically refreshing the datasource within the data grid and move to the next item in the table. Eg.After the button is clicked it Updates the "progress" column value to "1" and then refresh the data set and then call the .MoveNext to move the cursor to the next item in the table. It works but only executes once and then stops moving. The dataset refreshes fine but the .MoveNext is the issue. I try moving it above the dataset but then it does not execute the problem. What am I doing wrong?
When you call TableAdapter.Fill(Table) it cause the BindingSource which is bind to Table moves to first record. So calling bindingSource.MoveNext() after filling the table always moves to second record.
If for any reason you want to move to next record after filling the table using table adapter, store the current position before fill and set the position to next record after fill:
int current = 0;
private void Button1_Click(object sender, EventArgs e)
{
current = bindingSource1.Position;
tableAdapter1.Fill(dataSet1.Table1);
bindingSource1.Position = Math.Min(current + 1, bindingSource1.Count - 1);
}

access database not updating in DataGridView after deletion of a row

I am developing an Application for Computers store and i need an option to delete a product from the store , so i created a DataGridView and the data source of it was the database file of access.
when i debugged for the first time , i deleted a row and it updated in the DataGridView and Updated in the Access database file , but when i exit the app an re-debug , the list shows the deleted row one more time (Althought it's not showen in the access database file).
and it also causes error (SystemNullReferenceException) now when i delete any row
Am using OleDb provider.
here is my code:
namespace CompStore
{
public partial class ProductRemove : Form
{
private string str = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=J:\C#\CompStore\Store.accdb";
OleDbConnection con;
OleDbCommand com;
public ProductRemove()
{
con = new OleDbConnection(str);
InitializeComponent();
}
private void ProductRemove_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'storeDataSet.Products' table. You can move, or remove it, as needed.
this.productsTableAdapter.Fill(this.storeDataSet.Products);
}
private void button1_Click_1(object sender, EventArgs e)
{
con.Open();
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
DataGridViewRow delrow = dataGridView1.Rows[i];
if (delrow.Selected == true)
{
try
{
com.CommandText = "DELETE FROM Products WHERE ProductID=" + dataGridView1.Rows[i].Cells[0].Value + "";
com.Connection = con;
int count = com.ExecuteNonQuery();
}
catch (Exception ex) { MessageBox.Show(ex.ToString()); }
dataGridView1.Rows.RemoveAt(i);
}
}
con.Close();
}
}
}
I think the issue is that you are removing items as you move through them.
what may help is to create a list of id's to remove. then at the end remove them all and rebind the grid.
something like this:
var idsToRemove = new List<int>();
var rowsToRemove = new List<int>();
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
DataGridViewRow delrow = dataGridView1.Rows[i];
if (delrow.Selected == true)
{
try
{
//com.CommandText = "DELETE FROM Products WHERE ProductID=" + dataGridView1.Rows[i].Cells[0].Value + "";
//com.Connection = con;
//int count = com.ExecuteNonQuery();
idsToRemove.add(dataGridView1.Rows[i].Cells[0].Value);
}
catch (Exception ex) { MessageBox.Show(ex.ToString()); }
//dataGridView1.Rows.RemoveAt(i);
//^this changes the list length throws things off
rowsToRemove.Add(i);
}
}
con.Open();
com.CommandText = "DELETE FROM Products WHERE ProductID in(" + string.join(',', idsToRemove.ToArray() + ")";
con.Close();
//now rebind your grid so it has the right data
// or for each row to remove dataGridView1.Rows.RemoveAt(arow)
hope this helps
I think this code might work for solving your DataGridView problem (I use this code for myself):
private void button1_Click_1(object sender, EventArgs e)
{
foreach (DataGridViewRow item in this.datagridview1.SelectedRows)
{
datagridview1.Rows.RemoveAt(item.Index);
}
}
(Writing this complete foreach code snippet will be better than just writing the statement inside it, make sure this code snippet is outside the for loop!)
You can write this code before writing the code for deleting the row(s) of the database.
Hope this helps for you too. Send me a response when you(or anyone else) try this code to tell if it worked or not.

Datagridview updation bug

In my my project, I wrote a code such that if there is no data in the DGV it should not be updated, but even though data is not there when I click on the row which is empty and comes by default, and then on update button, it is getting updated. Please help me to fix the issue. The code I am using is:
private void btnUpdate_Click(object sender, EventArgs e)
{
if (dataGridView2.SelectedCells.Count == 0 )
{
MessageBox.Show("There are no any records to update");
}
else
{
SqlConnection con = Helper.getconnection();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
con.Open();
cmd.CommandType = CommandType.Text;
string PrjName = txtPrjNmae.Text;
string Description = txtPrjdescription.Text;
DateTime Date = dateUpdate.Value;
dateUpdate.Format = DateTimePickerFormat.Custom;
dateUpdate.CustomFormat = "dd/MM/yy";
string Size = txtPrjSize.Text;
string Manager = txtPrjManager.Text;
cmd.CommandText = "Update Projects set Description='" + Description + "', DateStarted='" + Date + "',TeamSize='" + Size + "',Manager='" + Manager + "' where ProjectName= '" + PrjName + "' ";
MessageBox.Show("Project Details are updated");
dataGridView2.Update();
dataGridView2.Refresh();
cmd.ExecuteNonQuery();
con.Close();
}
BindData3();
}
You can prevent user from adding new row by click on the last row of datagridview via settig AllowUserToAddRows = false
Check this
dataGridView2.Rows.Count > 0
in a condition
Instead of checking if (dataGridView2.SelectedCells.Count == 0 )
Do this
if( dataGridView2.Rows.Count > 0)
{
}
This will only do conditions if there is more than 0 rows.
first set
dataGridView2.AllowUserToAddRows = false
or
check every time while updating.
dataGridView2.Rows.Count > 0
or
if(dataGridView2.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString() != " ")
//do ur update here
Since you are letting the users to insert row through a different form (not through grdiview) first hide the empty row which is displayed by default as AllowUserToAddRow property is set to true, You have to set this property to false.
Still if you are allowing the users to add empty row to the grid in some other way then you have to validate it when user click update button. One approach i could think of is,
Check if the selected row has one of the mandatory cell value. Assume ProjectName is mandatory value then you can write a logic as follows,
selectedRow.Cells["ProjectName"] here ProjectName is column name.
private void btnUpdate_Click(object sender, EventArgs e)
{
//Get the selected row
DataGridViewRow selectedRow = dataGridView1.SelectedRows[0];
//Check if Project Name cell in the selected row null or empty
if (string.IsNullOrWhiteSpace(selectedRow.Cells["ProjectName"].Value.ToString()))
{
MessageBox.Show("There are no any records to update");
}
else
{
}
}

Categories

Resources