C# Clear/Reset Listbox populated with Datasource - c#

I have some methods that lists a variety of details in multiple Listboxes that can be added to a client, e.g. different crimes. The method below selects all the crimes from the CriminalRecord table where the ClientId = selected client's id and then populates the listCriminalRecord listbox with this data.
private void PopulateCriminalRecord()
{
string query = "SELECT * FROM CriminalRecord " +
"a INNER JOIN ClientCriminalRecord b ON a.Id = b.CriminalRecordId " +
"WHERE b.ClientId = #ClientId ORDER BY Crime ASC";
using (connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(query, connection))
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
command.Parameters.AddWithValue("#ClientId", newId);
DataTable dTable = new DataTable();
adapter.Fill(dTable);
listCriminalRecord.DisplayMember = "Crime";
listCriminalRecord.ValueMember = "Id";
listCriminalRecord.DataSource = dTable;
}
}
When the user is finished with entering the client's details, they will click a button, be prompted with a message etc etc.
private void btnFinish_Click(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show("Are you sure you've finished & filled in all of the Client's details?", "Save and exit", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
DisableStep2();
EnableStep1();
}
}
The EnableStep1(); method just enables and clears some textboxes and the DisableStep2(); method does the same but disables some textboxes. After this, I want all of the listboxes to be reset/cleared. I've tried listCriminalRecord.Items.Clear() but it expresses an error. I'm unsure on how to do this.
Any help would be fantastic.

Try this:
listCriminalRecord.DataSource = null;

Related

Update DataGridView Checked Record to the Database

So I have this DataGridView on which there are two columns which I am retrieving from my SQL Server database. Now, in the second column, we have a bit field which shows as a CheckBox in my Windows Application designer. So, I want to, on CellContentClick event be able to update the value that just got deselected into my database. But seems like I am going nowhere.
Here is my code below:
private void gvTurnOffNotifications_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
foreach (DataGridViewRow row in gvTurnOffNotifications.Rows)
{
DataGridViewCheckBoxCell cell = row.Cells[1] as DataGridViewCheckBoxCell;
//We don't want a null exception!
if (cell.Value != null)
{
bool result = Convert.ToBoolean(row.Cells[1].Value);
if (result == true)
{
//It's checked!
btnUpdateTurnOff.Enabled = true;
myConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (mySQLConnection = new SqlConnection(myConnectionString))
{
int temp = 1;
bool change = false;
string procedureName = "update UsersNotified Set AllowNotification='" + change + "' where AllowNotification='" + false+ "'";
mySQLCommand = new SqlCommand(procedureName, mySQLConnection);
mySQLCommand.CommandType = CommandType.Text;
mySQLCommand.Connection = mySQLConnection;
mySQLCommand.Connection.Open();
mySQLCommand.ExecuteNonQuery();
}
}
}
}
}
And then when I click on my "Update" button, I want to send the updated griddata for storing in my database as below:
private void btnUpdateTurnOff_Click(object sender, EventArgs e)
{
myConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (mySQLConnection = new SqlConnection(myConnectionString))
{
mySQLDataAdapter = new SqlDataAdapter("spGetAllUpdatedNotifications", mySQLConnection);
mySQLDataAdapter.SelectCommand.CommandType = CommandType.StoredProcedure;
mySQLCommand.Connection = mySQLConnection;
mySQLCommand.Connection.Open();
DataSet ds = new DataSet();
mySQLDataAdapter.Fill(ds);
mySQLDataAdapter.UpdateCommand = mySQLCommand;
mySQLDataAdapter.Update(ds);
}
}
The spGetAllUpdatedNotifications object in my Update block is a stored procedure I am calling just to retrieve the records from the database so I can update them on the fly in my DataSet. Here is the definition below:
create proc spGetAllUpdatedNotifications
as
begin
SELECT UserName, AllowNotification FROM UsersNotified where AllowNotification=1
end
GO
For more context: When my form loads, I am selecting all the records from the database which have their AllowNotification field set to bit 1 (true in C#) and once a user unticks a specific user (in other words, that user would not be allowed to receive notifications anymore) and once I click on the Update button, it should set the property to false (bit 0 in the database).
Instead of updating the one record which I have deselected, it updates all of them. "All" in this case are the records which have AllowNotification=1. I only want to set AllowNotification=0 for the deselected/unchecked record only
Any suggestions on how I can go about achieving this?
I am not sure what logic makes you to loop thru all the rows of the DataGridView just to update one row in the database.
If you want to update AllowNotification value for the username for which checkbox is checked or unchecked the logic would be this.
Figure out the updated value of the checkbox which is clicked in the gridview.
Store the updated value (True or False) in a boolean variable.
Retrieve the corresponding username of from the other cell of the same row the gridview.
Execute update query with criteria "WHERE UserName = {userName}".
You need to write CellContentClick event of the DataGridView as following.
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 1) //Assuming Checkbox is displayed in 2nd column.
{
this.dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
var result = this.dataGridView1[e.ColumnIndex, e.RowIndex].Value;
var userName = this.dataGridView1[0, e.RowIndex].Value; //Assumin username is displayed in fist column
var connectionString = "Your Connection String";
//Set value of your own connection string above.
var sqlQuery = "UPDATE UsersNotified SET AllowNotification = #allowNotification WHERE UserName = #userName";
using (var connection = new SqlConnection(connectionString))
{
using (var command = new SqlCommand(sqlQuery, connection))
{
command.CommandType = CommandType.Text;
command.Parameters.Add("#allowNotification", SqlDbType.Bit).Value = result;
command.Parameters.Add("#UserName", SqlDbType.NVarChar).Value = userName;
connection.Open();
command.ExecuteNonQuery();
}
}
}
}
This should help you resolve your issue.
I have a partial solution (It doesn't work a 100% but at least its a step in the right direction):
private void gvTurnOffNotifications_SelectionChanged(object sender, EventArgs e)
{
if (gvTurnOffNotifications.SelectedCells.Count > 0)
{
int selectedrowindex = gvTurnOffNotifications.SelectedCells[0].RowIndex;
DataGridViewRow selectedRow = gvTurnOffNotifications.Rows[selectedrowindex];
getUserSelected = Convert.ToString(selectedRow.Cells["UserName"].Value);
MessageBox.Show(getUserSelected);
foreach (DataGridViewRow row in gvTurnOffNotifications.Rows)
{
DataGridViewCheckBoxCell cell = row.Cells[1] as DataGridViewCheckBoxCell;
//We don't want a null exception!
if (cell.Value != null)
{
//It's checked!
btnUpdateTurnOff.Enabled = true;
myConnectionString = ConfigurationManager.ConnectionStrings["FSK_ServiceMonitor_Users_Management.Properties.Settings.FSK_ServiceMonitorConnectionString"].ConnectionString;
using (mySQLConnection = new SqlConnection(myConnectionString))
{
bool change = false;
string procedureName = "update UsersNotified Set AllowNotification='" + change + "' where UserName='" + getUserSelected + "'";
//MessageBox.Show(cell.Value.ToString());
mySQLCommand = new SqlCommand(procedureName, mySQLConnection);
mySQLCommand.CommandType = CommandType.Text;
mySQLCommand.Connection = mySQLConnection;
mySQLCommand.Connection.Open();
mySQLCommand.ExecuteNonQuery();
}
}
}
}
}
Problem is that it just takes the first row without me having selected the row I want to deselect.

C# Displaying a sql database object's name in a label.Text property on "SelectedIndexChanged" Event

I am trying to make a small contact book that takes contacts details from a mssql database.It has 3 tables: contacts, last_talk(last time i talked with a contact+short description of the discussion), and another table(that has both primary keys from the first 2 tables )
On the form(tab of tabcontrol) where i display the contacts, i have added 2 listboxes, one loads and displays the contacts names, and the second listbox loads the "Last talk" list for every contact i select depending how many "talks" i had with a contact.
What i am trying to do now is: when i select a contact, i also want to display near the listboxes, some labels for the contact name, company, etc, that change their text to the database entry for the selected contact's name/company...
Here is a part of the code:
private void lstContactList_SelectedIndexChanged(object sender, EventArgs e)
{
PopulateTalkList();
PopulateContactLabels();
}
private void ContactBookForm_Load(object sender, EventArgs e)
{
PopulateContactList();
}
private void PopulateContactList()
{
string query = "SELECT * FROM Contact";
using (connection = new SqlConnection(connectionString))
using (SqlDataAdapter adapter = new SqlDataAdapter(query, connection))
{
connection.Open();
DataTable contactTable = new DataTable();
adapter.Fill(contactTable);
lstContactList.DisplayMember = "Name";
lstContactList.ValueMember = "Id";
lstContactList.DataSource = contactTable;
}
}
here is the method that i try to use to change the labels:
private void PopulateContactLabels()
{
string query = "SELECT * FROM Contact";
using (connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(query, connection))
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
connection.Open();
SqlDataReader rdr = command.ExecuteReader();
while (rdr.Read())
{
lblContactName.Text = rdr["Name"].ToString();
lblCompany.Text = rdr["Company"].ToString();
lblOccupation.Text = rdr["Occupation"].ToString();
lblPhoneNumber.Text = rdr["PhoneNumber"].ToString();
lblEmail.Text = rdr["Email"].ToString();
}
rdr.Close();
connection.Close();
}
}
And it does change the labels, but it selects the last contact added to the database, and it doesn't change when i select another contact.
What am i doing wrong?
That's because in your PopulateContactLabels method, you are selecting the whole Contact table and then reading through the whole list, so it's always the last one which is shown.
You need a query more like SELECT * FROM Contact WHERE ContactId = #contactID, and then add the contactId (or whatever value you are using to find the contact) as a parameter on the SqlCommand object.

Adding datatable row and column and updating datagridview

string conString = "Server=192.168.1.100;Database=product;Uid=newuser;Pwd=password";
MySqlConnection conn = new MySqlConnection(conString);
DataTable dt = new DataTable();
DataRow row = dt.NewRow();
conn.Open();
//cmd = conn.CreateCommand();
//cmd.CommandText = "Select * From tblindividualproduct";
if (e.KeyCode == Keys.Enter)
{
if (txtBarcode.Text == "")
{
MessageBox.Show("Please Fill the correct ProductID");
}
else
{
string sql = "Select * From tblindividualproduct where ProductID = #ProductIdText";
using (var adapt = new MySqlDataAdapter(sql, conn))
using (var cmd = new MySqlCommandBuilder(adapt)) //Not sure what you need this for unless you are going to update the database later.
{
adapt.SelectCommand.Parameters.AddWithValue("#ProductIdText", txtBarcode.Text);
BindingSource bs = new BindingSource();
adapt.Fill(dt);
bs.DataSource = dt;
dgItems.ReadOnly = true;
dgItems.DataSource = bs;
}
}
}
How do I make the results to add, not just replace the last result. This is the whole code as requested. I just dont know if it needs manually adding of rows or there is an easy way to make it. Thank in advance
First of all, you should use Parameterized SQL to avoid SQL Injection.
Then you just need to put the code you have in an event handler of some sort. I would think the user would probably hit the enter key or something in the TextBox.
As long as you don't clear your DataTable it will just keep adding rows every time you run the query. If you want to clear the table at some other point in your code just call dt.Clear().
Something like this should get what you want and be safe from injection:
private void txtBarCode_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
if(String.IsNullOrEmpty(txtBarcode.Text))
{
MessageBox.Show("Please Fill the correct ProductID");
}
else
{
string sql = "Select * From tblindividualproduct where ProductID = #ProductIdText";
using (var adapt = new MySqlDataAdapter(sql, conn))
using (var cmd = new MySqlCommandBuilder(adapt)) //Not sure what you need this for unless you are going to update the database later.
{
adapt.SelectCommand.Parameters.AddWithValue("#ProductIdText", txtBarCode.Text);
BindingSource bs = new BindingSource();
adapt.Fill(dt);
bs.DataSource = dt;
dgItems.ReadOnly = true;
dgItems.DataSource = bs;
}
}
}
}
Then make sure you have attached this event to your TextBox somewhere in your Form class like this:
this.txtBarCode.KeyUP += txtBarCode_KeyUp;
Now when the user types in the box and presses enter the query will run and the results will display in the DataGridView. No need to manually add columns and rows, the adapt.Fill(dt); Will do that for you.

reducing stock by one on selection

I am trying to select film by using on select command, print the title in a label once selected.. that works well.
next part is the selected film will then decrement 1 from the database stock on button click. This is where I think I am getting confused, its showing no errors until the button click takes place.
C# code for update query
protected void Button2_Click(object sender, EventArgs e)
{
var myquery = string.Format("UPDATE DVD SET Stock = Stock - 1");
da.InsertCommand = new OleDbCommand("INSERT INTO DVD (Stock) VALUES (#MessageLabel)", conn);
{
da.InsertCommand.Parameters.AddWithValue("#Stock", MessageLabel.Text);
conn.Open();
da.InsertCommand.ExecuteNonQuery();
using (OleDbCommand cmd = new OleDbCommand(myquery, conn))
cmd.ExecuteNonQuery();
conn.Close();
conn.Dispose();
}
}
Previous code for select event
public void Latest_DVD()
{
{
using (OleDbDataAdapter dataquer = new OleDbDataAdapter("SELECT Title,Category,Director,Stock,Year FROM DVD ", conn))
{
dataquer.Fill(dt);
}
}
DG_Latest.ShowHeader = true;
DG_Latest.DataSource = dt;
DG_Latest.DataBind();
conn.Close();
conn.Dispose();
}
protected void Latest_DVD_SelectedIndexChanged(Object sender, EventArgs e)
{
GridViewRow row = DG_Latest.SelectedRow;
MessageLabel.Text = "You selected to rent " + row.Cells[1].Text + ".";
}
so I am thinking I have the query wrong and possibly nor retrieve the update from the label but maybe the on select its self... I am not sure through.
the error it is showing is
Data type mismatch in criteria expression.
just after the connection is open
As #afzalulh said, remove the insert part. And change myquery string to be:
var myquery = string.Format("UPDATE DVD SET Stock = Stock - 1 WHERE Title = #Title");
var row = DB_Latest.SelectedRow;
var title = row.Cells[0].Text;
var cmd = new OleDbCommand(myquery, conn);
cmd.Parameters.AddWithValue("#Title", title);
With that, you only update Stock for the selected DVD title only. Without adding WHERE clause, the query will decrease stock for all DVDs.
You want to update stock, there's no need to insert. I believe this is what you want:
protected void Button2_Click(object sender, EventArgs e)
{
var myquery = string.Format("UPDATE DVD SET Stock = Stock - 1");
conn.Open();
using (OleDbCommand cmd = new OleDbCommand(myquery, conn))
cmd.ExecuteNonQuery();
conn.Close();
conn.Dispose();
}
EDIT: myquery should include WHERE as suggested by har07. Otherwise it will reduce all DVD's stock by 1.

SQL Command Builder Query values

I have a SQLDataAdapter, in my query i am fetching two fields, ID(PK), Name.
I registered a sql command builder to my data adapter so i don't have to write queries to update table in database.
when I call the da.update() method, sql throws error that cannot insert null into DimensionID, due to this error, i have to select this field too in my dataset, and then i filled this field in grid with appropriate value. then da.update() worked.
Now the problem is that I don't want this field to appear in my gird, when i set its visible property to false, command builder omits this column in query. To cater this issue I have to set the column width to 0, but there is still a tiny line in my grid.
Is there a better way to handle this situation ? except that I manually write queries.
Below is Code to Populate Grid;
private void frmAttributes_Load(object sender, EventArgs e)
{
ds.Tables.Add("Attributes");
SqlCommand cmd = new SqlCommand();
cmd.Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
cmd.CommandText = "select ID,Attribute,Code,DimensionID from DimensionAttribute where dimensionid = " + SelectedAttribute;
da.SelectCommand = cmd;
cb.DataAdapter = da;
da.Fill(ds,"Attributes");
this.dgvAttributes.DataSource = ds.Tables["Attributes"];
this.dgvAttributes.Columns["ID"].Visible = false;
this.dgvAttributes.Columns["DimensionID"].Width = 0;
}
and here is the code behind Updated Button:
private void btnOk_Click(object sender, EventArgs e)
{
if (ds.HasChanges())
{
DialogResult d = new DialogResult();
d = MessageBox.Show("Are you sure you want to save changes to database?", this.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (d == DialogResult.Yes)
{
try
{
fillDimensionID();
da.UpdateCommand = cb.GetUpdateCommand();
da.InsertCommand = cb.GetInsertCommand();
da.DeleteCommand = cb.GetDeleteCommand();
da.Update(ds,"Attributes");
this.DialogResult = DialogResult.OK;
this.Close();
}
catch (Exception)
{
throw;
}
}
else
{
return;
}
}
}
This is a problem with AutoGeneratedCommands. They require every attribute assigned a proper value before update is triggered.
You can adopt either of the following:
Modify the column DimensionID to accept null values; or
Write your own update SP in the database and register it as UpdateCommand with your data adapter.
hope this will show you the path.

Categories