Refreshing ListBox Database values on database Update C# - c#

So i have read this question a few times somewhere else but after reading all those question i still have a working solution for it.
The problem is that i am populating a ListBox with Access Database information which you can see below:
private void FinancienData_Load(object sender, EventArgs e)
{
try
{
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
string query = "select * from Betaald where Maand='Januari'";
command.CommandText = query;
OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
listBox4.Items.Add(reader["Autoverzekering"].ToString());
listBox4.Items.Add(reader["Brabant Water"].ToString());
listBox4.Items.Add(reader["Eigen Risico Nicolas"].ToString());
listBox4.Items.Add(reader["Essent"].ToString());
listBox4.Items.Add(reader["Extra"].ToString());
listBox4.Items.Add(reader["Gemeenschappelijke Heffingen"].ToString());
listBox4.Items.Add(reader["Huur"].ToString());
listBox4.Items.Add(reader["Reiskosten Nicolas"].ToString());
listBox4.Items.Add(reader["RKDVC"].ToString());
listBox4.Items.Add(reader["Telefoonrekening Nicolas"].ToString());
listBox4.Items.Add(reader["Telefoonrekening Wendy"].ToString());
listBox4.Items.Add(reader["Woonverzekering"].ToString());
listBox4.Items.Add(reader["Ziggo"].ToString());
listBox4.Items.Add(reader["Zorgverzekering Nicolas"].ToString());
listBox4.Items.Add(reader["Zorgverzekering Wendy"].ToString());
}
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error" + ex);
}
}
This all works fine, BUT there is also a way which a user can update the database values. This is being done as follow:
private void button1_Click(object sender, EventArgs e)
{
try
{
connection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connection;
string query = "update Betaald set Autoverzekering='JA'";
command.CommandText = query;
command.ExecuteNonQuery(); //is nu non-query omdat je data insert
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error" + ex);
}
This update works, the value is being changed in the database. Though the problem is that the value wont update in the ListBox where it is displayed... I need to find an easy way that when the user presses that button, it wont only update in the Access database but also in the ListBox (without having to restart the entire form).
Already try'd multiple things i read about (listBox4.DataSource, ListBox RefreshItems, etc. ) but for some reason i cant get it to work (probably because im quite new to C# and .NET).
Could anyone help me out?
Thanks in advance!

In your private void FinancienData_Load method, you don't bind your database set to your listbox, but instead you are reading the rows from a table, adding ListBoxItems containing the row results to your listbox. This is mainly why the listBox4.DataSource binding doesn't work.
To make the update work, I'd recommend refactoring the code a little: How about putting the code that loads the values from the database into its own method, e.g. void LoadDataFromDb() . Once done, you can simply call this method after you updated the values. The method will then fetch the updated values from the database table and fill the listBox again. Don't forget to add listBox4.Items.Clear() to your LoadDataFromDb() method, otherwise you'll continously add new items to the listBox, instead of "refreshing" items.

Related

I'm facing a problem, where it is taking so much time to display a list thad is added to a database

Iam currently working on a book management project and I'm using SQL Server from Visual Studio. I have a Book Category table in the database and I'm trying to place it in a combobox.
This the code - I don't see anything wrong with it but the categories are taking so long to be visible in the combobox.
Also the list is repetitive, is it maybe because of the while Loop? If so is there any way to fix it?
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
con.ConnectionString = (#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\malek\source\repos\BookStore\BookStore\BOOKDB.mdf;Integrated Security=True");
scmd.Connection = con;
con.Open();
scmd.CommandText = "SELECT CATEGORY FROM BOOKCAT";
var rd = scmd.ExecuteReader();
while (rd.Read())
{
List.Add(Convert.ToString(rd[0]));
}
int i = 0;
while (i < List.LongCount())
{
comboBox1.Items.Add(List[i]);
i = i + 1;
}
}
catch (Exception EX)
{
MessageBox.Show(EX.Message);
}
finally
{
con.Close();
}
}
What did I miss?
NOTE: I am not getting any errors!!
How do you mean with data binding?
Like this
var da = new SqlDataAdapter(
"SELECT DISTINCT CATEGORY FROM BOOKCAT ORDER BY CATEGORY"
#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Users\malek\source\repos\BookStore\BookStore\BOOKDB.mdf;Integrated Security=True"
);
var dt = new DataTable();
da.Fill(dt);
categoryComboBox.DisplayMember = "CATEGORY";
categoryComboBox.ValueMember = "CATEGORY";
categoryComboBox.DataSource = dt;
And when you want the thing the user selected:
var cat = categoryComboBox.SelectedValue as string;
Simple eh?
It gets even easier if you use a strongly typed dataset; for that you just add a new DataSet type file to your project (must use net framework not net core/5+), drag your db into your dataset, add a query to the category TableAdapter that gets the distinct categories (like above) then open the data sources window, change Category to a combo and tag it onto the form. No code to write; vs will write it all
Based on the code you've posted, it looks like you're loading the categories from the database in the SelectedIndexChanged event of comboBox1.
So, every time you choose a new item from comboBox1 you're executing this code; you're going to the database and loading everything from the BOOKCAT table and you're putting those items into List and comboBox1. That is why you're seeing duplicated categories. It's probably also why it takes so long for a category to be visible in the ComboBox.
You probably don't want to load the ComboBox items from the database every time the selected index changes, so you should do that somewhere else. For example, you could do it in the Form's constructor, or in the 'Load' event.

How to read and write DataGridView data to Sql Table

I am currently working on a database system. In the system a user can search for a specific member using their ID. Searching for them filters all DataGridView results to just that specific member.
private void button3_Click(object sender, EventArgs e)
{
dataGridView1.ReadOnly = false;
using (SqlConnection con = new SqlConnection(constring))
{
int id = Convert.ToInt32(textBox1.Text);
con.Open();
DataTable FindAaron = new DataTable();
SqlDataAdapter adapt = new SqlDataAdapter("SELECT * FROM MembersTable WHERE MemberID =" + id, con);
adapt.Fill(FindAaron);
dataGridView1.DataSource = FindAaron;
con.Close();
}
}
This code filters the DataGridView results down to one row from the table 'MembersTable'. The user can now physically click on the table cell and edit the data as much as they want. Once they are finished they hit a 'Save Changes' button which I want to save the changes they made, update the source table and refill the DataGridView with all the members, now with updated info. This is the code I have behind the 'Save Changes' button at the moment.
try
{
//MemberClass.UpdateMember();
this.membersTableTableAdapter.Update(mainDatabaseDataSet.MembersTable);
dataGridView1.Refresh();
MessageBox.Show("Details updated");
}
catch
{
MessageBox.Show("An error has occured");
}
This unfortunately does not update the DataGridView in the form to display all the updated data or save the data that has been edited back to the Sql table. Have puzzled over this for a few days and can't figure out what I'm doing wrong. Any and all help is much appreciated.
Actually there is no connection seen between membersTableTableAdapter and adapt or mainDatabaseDataSet.MembersTable and FindAaron.
Try as following;
//Get the changed data
DataTable changes = FindAaron.GetChanges();
if (changes != null)
{
//Update data
adapt.Update(changes);
}

Refresh datagridview after insert on the same form

I have a form with a datagridview and input boxes with a button to insert values.
I would like the datagridview to refresh once the button is clicked. I have tried the datagridview.refresh() and datagridview.update options. The data only appears once the application has been closed and reopened.
Here is my code:
class cFunction
{
public static void DoSQL(string Query)
{
SqlConnection Connection = new SqlConnection(#" Data Source=(LocalDB)\v11.0;AttachDbFilename=C:\Users\Zahida\Desktop\RapidsoftSupport\RapidsoftSupport\MainData.mdf;Integrated Security=True");
SqlCommand Command = new SqlCommand(Query, Connection);
Command.Connection.Open();
Command.ExecuteNonQuery();
Command.Connection.Close();
Connection.Close();
}
}
private void btnAdd_Click(object sender, EventArgs e)
{
cFunction.DoSQL("INSERT INTO Problem(SYSTEM_ID,SUBJECT, KEYWORDS) VALUES('" + SID + "','" + txtSubject.Text + "','" + txtKeywords.Text + "')");
this.problemTableAdapter.Fill(this.mainDataDataSet1.Problem);
}
Any help?
The grid control must bind to active and alive data source, you push some records to dataset when your program load and grid cache theme to show.
You can use binding or run select query after every insert occurred to update dataset with new records .
Zahida Kazi,
At first, you don't need to push two closure:
Command.Connection.Close();
Connection.Close();
I didn't see a gridview bindings. If you are not set a bindings just now, I can suggest you to use DataTable to create Data and bind by DataGridView.DataSource = DataTable.
When data updated, you can use two ways to update gridview's data
you may want to update proper grid column value
you may re-bind datasource of gridview

ASPxGridView and LinqServerModeDataSource: Inserting and updating rows without showing all columns in grid

How do I use a LinqServerModeDataSource to insert or edit rows of the underlying data table when I do not show all fields of that table in the ASPxGridView?
Similar questions have been asked, but this is not a duplicate. For example, this one asks about a LinqServerModeDataSource and the accepted answer tells how to use an ordinary SqlDataSource.
I have an ASPxGridView hooked up to a table via a LinqServerModeDataSource. But I do not show all columns in the grid. For example, there are columns for the date created and some others that the user doesn't need to know about. I am allowing inline editing in the grid, but in the Inserting or Updating event, the new values passed are just a dictionary of the values displayed in the grid.
What about the other values? I would expect to be able to set any of the values for the underlying data row programmatically in the event handler, regardless of whether they are displayed and thus edited by the user. How do I get access to them and set the other values in the events of the LinqServerModeDataSource? I am having no luck reading the devexpress documentation.
I'm guessing that there must be a Linq class that hooks into the table that I can use in those events, similarly to the Selecting event. But how?
Here's what the Selecting event handler looks like... Is there not some similar interface I can use to access the underlying data in the other events?
protected void dsRecipients_Selecting(object sender, DevExpress.Data.Linq.LinqServerModeDataSourceSelectEventArgs e)
{
SmsRecipientsDataContext context = new SmsRecipientsDataContext();
IQueryable<NotificationParty> val = context.NotificationParties;
int notificationGroupID = Convert.ToInt32(Context.Session["NotificationGroupID"]);
val = val.Where(n => n.NotificationGroupID == notificationGroupID && n.Active);
e.KeyExpression = "ID";
e.QueryableSource = val;
}
As much as I hate answering my own question...
I can't figure out how to get this control to do what I want. However, a simple workaround is to handle the insert and update on the grid itself.
So, it's working now. I set the EnableUpdate and EnableInsert properties on the LinqServerModeDataSource to false, and simply handle the grid's RowInserting and RowUpdating events, where I go directly to the database.
For example, my inserting event handler is this:
protected void recipientsGrid_RowInserting(object sender, DevExpress.Web.Data.ASPxDataInsertingEventArgs e)
{
using (SqlConnection connection = new SqlConnection(App_Logic.Wrappers.DatabaseConnectionString()))
{
connection.Open();
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.Transaction = connection.BeginTransaction();
try
{
command.CommandText = " INSERT INTO NotificationParty(NotificationGroupID, FirstName, LastName, CellNumber, Active, UserCreated, DateCreated) VALUES " +
"(#NotificationGroupID, #FirstName, #LastName, #CellNumber, #Active, #UserCreated, GETDATE())";
command.Parameters.AddWithValue("#NotificationGroupID", Convert.ToInt32(Context.Session["NotificationGroupID"]));
command.Parameters.AddWithValue("#FirstName", e.NewValues["FirstName"]);
command.Parameters.AddWithValue("#LastName", e.NewValues["LastName"]);
command.Parameters.AddWithValue("#CellNumber", e.NewValues["CellNumber"]);
command.Parameters.AddWithValue("#Active", 1);
command.Parameters.AddWithValue("#UserCreated", Session["UID"]);
command.ExecuteNonQuery();
command.Transaction.Commit();
}
catch
{
command.Transaction.Rollback();
}
}
}
recipientsGrid.CancelEdit();
e.Cancel = true;
}
And my updating event handler is this:
protected void recipientsGrid_RowUpdating(object sender, DevExpress.Web.Data.ASPxDataUpdatingEventArgs e)
{
using (SqlConnection connection = new SqlConnection(App_Logic.Wrappers.DatabaseConnectionString()))
{
connection.Open();
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.Transaction = connection.BeginTransaction();
try
{
command.CommandText = " UPDATE NotificationParty SET FirstName = #FirstName, LastName = #LastName, CellNumber = #CellNumber, UserModified = #UserModified, DateModified = GETDATE() WHERE ID = #ID";
command.Parameters.AddWithValue("#ID", e.Keys[0]);
command.Parameters.AddWithValue("#FirstName", e.NewValues["FirstName"]);
command.Parameters.AddWithValue("#LastName", e.NewValues["LastName"]);
command.Parameters.AddWithValue("#CellNumber", e.NewValues["CellNumber"]);
command.Parameters.AddWithValue("#UserModified", Session["UID"]);
command.ExecuteNonQuery();
command.Transaction.Commit();
}
catch
{
command.Transaction.Rollback();
}
}
}
recipientsGrid.CancelEdit();
e.Cancel = true;
}

My datagrid's selection is lost when updating my database from the grid's bound dataset. Any workarounds?

I am using Xceed's Datagrid, bound to a dataset. I want to update the database when the datagrid's RowEditEnd is called. The problem is that in order to avoid concurrency violations when updating, I have to clear the dataset after update and refill it, like this:
public void UpdateDatabaseFromDataSet()
{
adapter.Update(exampleDataSet);
exampleDataSet.Clear();
adapter.Fill(exampleDataSet);
}
I think I have to do this because my dataset's primary autoincrement column "ID" does not match the values generated by the database. When I clear the dataset, it clears the datagrid and its selected cell. This is very annoying since, if you edit a cell and hit enter or a directional key, the cell and database will update fine, but your selection gets reset instead of navigating to the next row/cell. This makes entering data by hand very cumbersome.
Here is the method that creates the dataset:
public void InitDataSet(int tableid)
{
cmd = new SQLiteCommand("SELECT * FROM table_" + tableid, con);
adapter = new SQLiteDataAdapter(cmd);
cb = new SQLiteCommandBuilder(adapter);
try
{
exampleDataSet = new DataSet();
adapter.Fill(exampleDataSet);
prodDataSet.Tables[0].Columns[0].AutoIncrementSeed = -1;
prodDataSet.Tables[0].Columns[0].AutoIncrementStep = -1;
currenttableID = tableid;
}
catch (ApplicationException ex)
{
MessageBox.Show("Encountered an error.", "Error: " + ex.ToString());
}
}
Note that I have tried setting the tables autoincrementseed and autoincrementsteps to -1 but I still get concurrency violations if I don't refill the dataset.
I would really like my datagrid to work the way it does if I do not clear and refill the dataset. Is there anyway to avoid the concurrency violations I'm running into? Am I going about this the wrong way?
Thanks for your help.
-Steven
I don't exactly understand the complete problem but I might be able to give you something
When you don't clear the dataset and call "fill" it'll try to "merge" the records from the DB with the existing records. The clear forces your grid to refresh I guess.. losing the selected row.
With
Adapter.FillLoadOption = LoadOption.PreserveChanges (or other);
You can influence how records from the db that are changed are merged with the dataset.
Now there is one problem left and that is to determine the new autoinc value when an insert has taken place. You can catch the Adapter.RowUpdated
void Adapter_RowUpdated(object sender, SqlRowUpdatedEventArgs e)
{
if (e.StatementType==StatementType.Insert)
{
Select last autoinc value with ##Identity
e.Row["ID"] = last autoinc value
}
}
So :
Don't clear de datatable
Catch rowupdated and get the latest autoinc value in the db in put it in the new row
Evt. call fill to see if other users have made changes
Here is the code that ended up working for me, putting it here for other's benefits.
Here's my data providers update method (note that I was able to remove the extra fill call):
public void UpdateDatabaseFromDataSet()
{
adapter.Update(exampleDataSet);
}
And here is the RowUpdated event I'm using:
void adapter_RowUpdated(object sender, System.Data.Common.RowUpdatedEventArgs e)
{
if (e.StatementType == StatementType.Insert)
{
SQLiteCommand cmdNewID = new SQLiteCommand("SELECT last_insert_rowid()", con);
e.Row["RowID"] = cmdNewID.ExecuteScalar();
}
}

Categories