Handling "Dropdown does not contain selected item" Error - c#

I am having trouble with a particular situation. The values in my dropdownlist are as follows: 101, 102, 103, but at any point in time the use can add or deactivate items to the dropdown ex: 101, 104, 106.
I have this dropdownlist embedded into a listview edit item template. So if the user adds a record with value 102, then later on deletes this value they cannot edit this value because I get the above error.
So what I am trying to figure out is how I can handle this message to let the use know they cannot edit the record. What I have so far is the ListView_ItemEditing event handler:
protected void LV_Equipment_ItemEditing(object sender, ListViewEditEventArgs e)
{
LV_Equipment.EditIndex = e.NewEditIndex;
e.Cancel = true;
try
{
LV_Equipment.DataBind();
}
catch (Exception ex)
{
//This is telling the user they cannot edit the record.
AlertMessage("you cannot edit this record.");
}
DropDownList UnitIDDDL = (DropDownList)(LV_Equipment.EditItem.FindControl("DropDownList1"));
DropDownList DriverIDDDL = (DropDownList)(LV_Equipment.EditItem.FindControl("DDL_Insert_Drivers"));
//We need to get the driver for the selected unit in the listview.
int ID = DatabaseInteraction.GetUnitDriver(UnitIDDDL.SelectedValue);
//Now that we have the id we can set the ddl.
DriverIDDDL.SelectedValue = ID.ToString();
DriverIDDDL.DataBind();
}
So if the user tries to edit a valid item there is no problem. But if they try to edit a deactivated item from the listview they LV_Equipment.DataBind() method will fail, and the rest of the code will throw an error as the UnitIDDDL and DriverIDDDL are set as null.
Any ideas on how to make this workaround effective?

Ok, here's what you need to do.
Your data binding should be coming from a SQL query of some sort. Let's assume it looks something like this:
string query = "SELECT ItemNumber FROM TableName";
SqlConnection conn;
SqlDataAdapter da = new SqlDataAdapter(query,conn);
DataTable sqlTable = new DataTable("Test");
da.Fill(sqlTable);
LV_Equipment.DataSource = sqlTable;
What you'll want to do is change your query so that it looks something like this:
string query = "SELECT ItemNumber FROM TableName WHERE Active = 'True'";
That should solve your problem.
Add a return to your catch block:
try
{
LV_Equipment.DataBind();
}
catch (Exception ex)
{
//This is telling the user they cannot edit the record.
AlertMessage("you cannot edit this record.");
return; // don't continue to process
}

Related

Edit Multiple Cells on DataGrid then Save to database

I want to edit multiple cells in DataGrid, and when btnUpdate is clicked the cells I edited will be updated in database.
I have tried the ff code for btnUpdate:
DialogResult res = MessageBox.Show("Are you sure you want to apply changes?", "Confirm", MessageBoxButtons.YesNo);
if (res == DialogResult.Yes)
{
foreach (DataGridViewRow row in dgMain.SelectedRows)
{
DataTable d = dgMain.DataSource as DataTable;
long attendanceid = Convert.ToInt64(row.Cells["Attendance_Id"].Value.ToString());
EmployeeAttendance a = new EmployeeAttendance();
a.ProcAccountingAttendance_Update(attendanceid);
}
MessageBox.Show("Changes Successfully Saved!");
}
But the problem is it still doesnt Update the database.
First problem is you are going through selectedRows only which means if you changed multiple values and after all that you select only one row, only that one will be updated.
Next problem is that you are going through all selected rows, the ones with change and ones without it.
What I would do in your place is this:
Create public class like this:
class:
public class ChangedData
{
public Object primaryKey;
public Object columnName;
public Object columnValue;
}
Create public List<ChangedData> changedData; inside your form
Call cellValidating event and inside it check if old and new values are different, if they are different then do changedData.Add(new ChangedData { primaryKey = primaryKeyOfYourTable, columnName = dataGridView1.Columns[e.ColumnIndex].Name, columnValue.FormattedValue });
And finally when you press update button you go
this:
using(SqlConnection con...)
{
con.Open();
using(SqlCommand cmd = new SqlCommand("UPDATE YOURTABLE SET #ColumnName = #ColumnValue where PrimaryKeyColumn = #PrimaryKey", con);
{
cmd.Parameters.Add("#ColumnName");
cmd.Parameters.Add("#ColumnValue");
cmd.Parameters.Add("#PrimaryKey");
foreach(ChangedData cd in changedData)
{
cmd.Parameters["#ColumnName"].Value = cd.columnName.ToString();
cmd.Parameters["#ColumnValue"].Value = cd.columnValue.ToString();
cmd.Parameters["#PrimaryKey"].Value = cd.primaryKey.ToString();
cmd.ExecuteNonQuery();
}
}
con.Close();
}
Code I wrote is not tested and need editing since you haven't provided us with any code you have or structure of your database. If you need something else edit answer or comment.
UPDATE: I have finally solved the problem with the ff code:
BTW, I am using a stored procedure for my database
private void dgMain_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
string id = dgMain.Rows[e.RowIndex].Cells["Attendance_Id"].Value.ToString();
string columnname = dgMain.Columns[e.ColumnIndex].Name;
string value = dgMain.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
EmployeeAttendance a = new EmployeeAttendance();
a.ProcAccountingAttendance_UpdateByGroupIdDateFromTo(Convert.ToInt64(id),columnname,value);
}

NullReferenceException after displaying a table on DataGridView more than once

Edit 2: Turns out it only gives a NullReferenceException the first time. After that, it says that I am not allowed to change the ConnectionString property, even though I think I have closed it in the right places.
Thanks for taking the time to read this.
I am working on a WinForms application that uses an MS Access database, and I am currently having problems with an entry deletion feature I made.
So, I have a DataGridView that switches between 3 tables on a button click, and I have a function that deletes a row on a table that is currently open by clicking a button that is at the end of the row.
When I open my first table, and try to delete a row, it works just fine. However, if I open a different table afterwards and try to delete an entry, or even go back to the first table I opened, I get a NullReferenceException in the deletion function.
Here is the code to display one of the tables in DataGridView.
public DataTable Read()
{
connection.ConnectionString = connectionString;
OpenConnection(); //connection.Open() inside an if statement
dataTable.Clear();
OleDbCommand readStudentCommand = new OleDbCommand("select * from Students", connection); //display the whole list of students
OleDbDataReader reader = readStudentCommand.ExecuteReader();
dataTable.Load(reader);
connection.Close();
return dataTable;
}
Here is the code that deletes an entry
private void MainDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
connection.ConnectionString = connectionString;
if (ConnectionState.Closed == connection.State)
{
connection.Open();
}
var senderGrid = (DataGridView)sender;
if (e.RowIndex >= 0 && senderGrid.Columns[e.ColumnIndex] == MainDataGridView.Columns["Delete"])
{
//this function retrieves the first column value of the deleted row, which has the ID of the entry (works with any table).
DeleteEntry(MainDataGridView.Rows[e.RowIndex].Cells[0].Value.ToString()); //exception thrown here (System.Windows.Forms.DataGridViewCell.Value.get returned null)
MainDataGridView.Rows.RemoveAt(e.RowIndex);
}
and here is DeleteEntry()
private void DeleteEntry(string deletedID)
{
string tableName = null;
string idType = null;
if (studentsDisplayed)
{
tableName = "Students";
idType = "Student ID";
}
else if(booksDisplayed)
{
tableName = "Books";
idType = "BookID";
}
else if(loansDisplayed)
{
tableName = "Loans";
idType = "Loan ID";
}
string deleteCommand = String.Format("DELETE * FROM {0} WHERE [{1}] = {2}", tableName, idType, deletedID);
OleDbCommand deleteEntryCommand = new OleDbCommand(deleteCommand, connection);
deleteEntryCommand.ExecuteNonQuery();
SaveData(); //this method just calls Update() in a dataAdapter of a relevant table
connection.Close();
}
Thank you!
Edit:
As per request, here is the code that switches the table. It simply references the first function and sets the returned dataTable as DataSource.
private void StudentButton_Click(object sender, EventArgs e) //display students
{
try
{
if (!studentsDisplayed)
{
MainDataGridView.DataSource = studentDAL.Read(); //studentDAL is the class that works with the Students table of my DB.
studentsDisplayed = true; //these 3 are to avoid duplicated creation of the same table
booksDisplayed = false;
loansDisplayed = false;
ComboBoxChanger(); //don't mind this, it's for an irrelevant feature
CreateButtons(5);
}
}
catch
{
throw;
}
}
Okay, so turns out the problem was the fact that DeleteEntry(MainDataGridView.Rows[e.RowIndex].Cells[0].Value.ToString()) had a problem with the Cells[0] part. After the first time loading a table, the 0th cell just vanished. So, I rewrote the code so that instead of declaring tableName and idType in DeleteEntry(), they're declared in MainDataGridView_CellContentClick(), and then made the DeleteEntry() accept 3 idType and tableName as parameters, and changed the MainDataGridView.Rows[e.RowIndex].Cells[0].Value.ToString() argument to MainDataGridView.Rows[e.RowIndex].Cells[idType].Value.ToString(). Now it works just fine!

ComboBox.SelectedValue not working as expected

So I have a DataGridView which I am using as a “row selector” on a form, and a bunch of controls are bound to the bindingSource.
One of the bound controls is a ComboBox serving as a lookup which enables status choices for the rows, this is populated from a DataTable with data pulled from the DB.
The population of this box is without any issue.
When a given row is selected from the DGV the form controls display data from the given row as they should, however the “statusComboBox” is not quite playing the game.
If in the DGV, I choose a row that has a different status to one previously selected, it works as it should, however, if I choose a row with the same value to a previously selected row, instead of the box showing the DisplayMember it shows the ValueMember.
IT only seems to occur in the above scenario, where the rows selection only instigates a display response from the bound ComboBox providng a previous selection had a different “Status ID”. What have I dont wrong that would cause this behaviour?
So the form load looks like this
private void ProjectsForm_Load(object sender, EventArgs e)
{
InitBindingSource();
//// bind Selector
//ASMod$ this needs to be 'true' unless you explicitly declare columns
ProjectsDataGridView.AutoGenerateColumns = false;
ProjectsDataGridView.DataSource = ProjectsBindingSource;
GetData();
//Set GeneralStatusBox
Helpers.GeneralStatusInitLookup(statusComboBox, ProjectsBindingSource);
}
The ProjectBindingSource is initialised thus:
private void InitBindingSource()
{
ProjectsBindingSource = new BindingSource();
projectsBindingNavigator.BindingSource = ProjectsBindingSource;
ProjectsBindingSource.PositionChanged += new EventHandler(ProjectsBindingSource_PositionChanged);
}
A ProjectsAddDataBindings procedure, and the contained DataBindings.Add for the ComboBox (executed at the end of a GetData routine that additionally populated ProjectsBindingSource):
ProjectsAddDataBindings();
{
…
this.statusComboBox.DataBindings.Add("Text", ProjectsBindingSource, "GSID");
…
}
After the GetData block the GeneralStatusInitLookup populates the Lookup elements, in a helper class simply because it provides functionality to a number of different forms
public static void GeneralStatusInitLookup(System.Windows.Forms.ComboBox comboBox, BindingSource primaryBindingSource)
{
string statusFilter = "";
statusFilter = Helpers.GetStatusGroupFilter(EndeavourForm.FilterId);
if (statusFilter != "")
{
statusFilter = " WHERE " + statusFilter;
}
//// string statusFilter = ""; //// temp
string sql = "";
sql = "SELECT GSID, ShortName FROM GeneralStatus" + statusFilter + " ORDER BY Pos";
GeneralStatusDataTable = Helpers.Db.GetDataTable(sql);
comboBox.DataSource = GeneralStatusDataTable;
comboBox.DisplayMember = "ShortName";
comboBox.ValueMember = "GSID";
comboBox.DataBindings.Add(new Binding("SelectedValue", primaryBindingSource.DataSource, "GSID"));
}
And the DGV initiated row change is handled like this
private void ProjectsBindingSource_PositionChanged(object sender, EventArgs e)
{
try
{
// Update the database with the user's changes.
UpdateProjects();
statusComboBox.SelectedValue = (int)CurrentDataRowView.Row["GSID"];
}
catch (Exception)
{
}
}
private void UpdateProjects()
{
try
{
ProjectsDataAdapter.Update((DataTable)ProjectsBindingSource.DataSource);
DataHelper.CommitProposedChanges(projectsDataSet);
if (this.projectsDataSet.HasChanges() == true)
{
ProjectsBindingSource.EndEdit();
ProjectsDataAdapter.Update();
}
CurrentDataRowView = (DataRowView)ProjectsBindingSource.Current;
}
catch (InvalidOperationException)
{
throw;
}
catch (Exception)
{
throw;
}
}
Anyway I hope I haven't swamped readers with to much code, but frankly I cant see where this is going wrong. So any help would be greatly appreciated.
This was a simple solution in the end. Both the GeneralStatusInitLookup() and the ProjectsAddDataBindings() blocks made use of DataBindings.Add ... For the lookup table this was fine, but with the binding to the main table; the later, I had used "Text" as the propertyName parameter.

Update the content of a table in .Net

I am trying to update a record in .Net. I can't figure it out how to do it. I need to specify that I have a DataGridView that displays all the records, and when I click a cell, it shows in separate TextBoxes the content of all columns. So that is I am trying to do, when I modify the TextBoxes and click the Button for Update, to update the row which contains the clicked cell.
I have tried to do this
private void button2_Click(object sender, EventArgs e)
{
DataRow[] row_update = ds.Tables["Plane"].Select("airline_id = " + aidbox.Text);
try
{
row_update["airline_id"] = int.Parse(aidbox.Text);
row_update["plane_id"] = int.Parse(pid_box.Text);
row_update["name"] = name_box.Text;
row_update["model"] = model_box.Text;
row_update["f_seats"] = int.Parse(fc_box.Text);
row_update["s_seats"] = int.Parse(sc_box.Text);
row_update["b_seats"] = int.Parse(bs_box.Text);
row_update["p_weight"] = float.Parse(weight_box.Text);
}
catch (Exception ex) { MessageBox.Show(ex.Message); }
try
{
builder = new SqlCommandBuilder(data_adapter);
data_adapter.UpdateCommand = builder.GetUpdateCommand();
data_adapter.Update(ds, "Plane");
}
catch (SqlException ex) { MessageBox.Show(ex.Message); }
}
}
but I get this error Table doesn't have a primary key. in this line DataRow row_update = ds.Tables["Plane"].Rows.Find(aidbox.Text); Here I am trying to find the row that has the id in the aidbox (because I assume that the id is unique and never changes only the other values).
Can anyone help me please with this
DataRows.Find method Gets a specified DataRow using the PrimaryKey index
If you cannot define a primary key for the datatable then could use DataTable.Select as it accepts any column in the filter expression
DataRowCollection.Find requires a primary key on the DataTable. Set the PrimaryKey property by creating an array of DataColumns. See the MSDN documentation. Or just use Select instead.
Your previous find() may work through this code,
DataColumn[] temp = new DataColumn[1];
temp[0] = ds.Tables["Plane"].Columns["airline_id"];
ds.Tables["Plane"].PrimaryKey = temp;
DataRow row_update = ds.Tables["Plane"].Rows.Find(aidbox.Text);

Transfer data to another table and make previous GridView empty

I have GridView. When I click a button, it sends data to another table and makes the previous GridView empty.
I have the following code for the button click, but it does not make the previous GridView empty.
protected void Button1_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
conn.Open();
string userApply = "insert into Company (CompanyName) select (JobTitle) from Jobs where JobTitle=JobTitle";
SqlCommand insertApply = new SqlCommand(userApply, conn);
try
{
insertApply.ExecuteNonQuery();
conn.Close();
Response.Redirect("ApplyJob.aspx");
}
catch (Exception er)
{
Response.Write(er.ToString());
}
finally
{
}
}
}
}
Are you clearing the previous gridview anywhere?
Maybe try this before your redirect:
grvPrevious.DataSource = null;
grvPrevious.DataBind();
it looks like you have your GridView in ApplyJob.aspx, since you are redirecting to that page in your try block and there you see the gridview holding some values. You may pass a query string along with ApplyJob.aspx and then in your form load of ApplyJob.aspx check for that query string. If you find the value then clear the Gridview. Something on the following line..
In your try block do :
Response.Redirect("ApplyJob.aspx?ClearGridView=YES");
In your Form_Load event of the ApplyJob.aspx check for the query string
if(Request.QueryString["ClearGridView"] != null && Request.QueryString["ClearGridView"] =="YES")
{
yourGridView.DataSource = null;
youGridView.DataBind();
}

Categories

Resources