I have an odd problem. In my program, a user manipulates dropdown boxes and presses an ADD button to fill in a listbox with the selected items. Eventually, I send these items to a MYSQL database with an INSERT command. When the user is hitting the ADD button, the items are added to a generic List and the listbox, and on postback everything seems fine and I can add stuff all day long. However, when I hit the Submit/save button, to send the data to the server, the list keeps copying the added data over and over again to itself on every postback no matter what causes the postback. I can see the result in the lstbox, and I can see the List.count going up.
I have no code in my page_load section. I do use a session property thing to hold the List data though.
public List<string> activityProp
{
get
{
if (HttpContext.Current.Session["codelist"] == null)
{
HttpContext.Current.Session["codelist"] = new List<string>();
}
return HttpContext.Current.Session["codelist"] as List<string>;
}
set
{
HttpContext.Current.Session["codelist"] = value;
}
}
and here is the code for the button. The sqlsetter() method just has a generic SQL command structure in it with an insert string. It is only fired from this button.
protected void cmdSave_Click(object sender, EventArgs e)
{
//this will use the 'test' class to do a rule check on the day
test therules = new test();
bool comp = therules.check(dayProp, timeProp, activityProp);
if (comp == true)
{
lblComp.Text = "You're ok!";
lblComp.ForeColor = Color.Green;
lblError.Text = "";
SQLdaysetter();
}
else
{
string zeerror = therules.getError();
lblComp.Text = "You're not ok!";
lblError.Text = "at " + zeerror;
lblComp.ForeColor = Color.Red;
lblError.ForeColor = Color.Red;
}
}
SQL stuff:
using (MySqlConnection conn = new MySqlConnection(ConfigurationManager.ConnectionStrings["theConnectionString"].ConnectionString))
{
conn.Open();
using (MySqlCommand cmdIns = new MySqlCommand(sqlstate, conn))
{
cmdIns.ExecuteNonQuery();
cmdIns.Dispose();
}
conn.Close();
}
Maybe this stuff isn't even related to the problem, any ideas where to look?
I had some things in the OnInit event and evidently they were getting run every time the page reloaded. I'm still not sure why
Jake, take 10 minutes and read up on the Page Life Cycle (especially the events section). It will save you valuable time in the future.
http://msdn.microsoft.com/en-us/library/ms178472.aspx
Related
I am trying to create a text input field with autocomplete functionality. The list of available options is huge (50,000+) and will need to be queried on TextChanged (after the first 3 characters have been entered).
I have a 99%-working solution with TextBox, setting AutoCompleteCustomSource to my new AutoCompleteStringCollection in the TextChanged event, but that results in occasional memory access violations due to a well-documented bug in the underlying AutoComplete implementation...
Microsoft Support say "Do not modify the AutoComplete candidate list dynamically during key events"...
Several SO threads: 1, 2, 3
These threads have some suggestions on how to prevent the exceptions but nothing seems to completely eliminate them, so I'm looking for an alternative. have tried switching to a ComboBox-based solution but can't get it to behave as I want.
After the user types the third character, I update the ComboBox's DataSource but the first item is automatically selected. The user is not able to continue typing the rest of the name.
The ComboBox items are not visible until the user clicks the triangle to expand the list
If the user selects the text they have entered and starts typing, I set DataSource to null to remove the list of suggestions. Doing this puts the cursor at the start of the text, so their characters appear in completely the wrong order!
My View:
public event EventHandler SearchTextChanged;
public event EventHandler InstrumentSelected;
public Instrument CurrentInstrument
{
get { return comboBoxQuickSearch.SelectedItem as Instrument; }
}
public IEnumerable<Instrument> Suggestions
{
get { return comboBoxQuickSearch.DataSource as IEnumerable<Instrument>; }
set
{
comboBoxQuickSearch.DataSource = value;
comboBoxQuickSearch.DisplayMember = "Name";
}
}
public string SearchText
{
get { return comboBoxQuickSearch.Text; }
}
private void comboBoxQuickSearch_TextChanged(object sender, EventArgs e)
{
if (SearchTextChanged != null)
{
SearchTextChanged(sender, e);
}
}
private void comboBoxQuickSearch_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter && InstrumentSelected != null)
{
InstrumentSelected(sender, e);
}
}
My Presenter:
private void SearchTextChanged(object sender, EventArgs e)
{
lock (searchLock)
{
// Do not update list of suggestions if:
// 1) an instrument has already been selected
// (the user may be scrolling through suggestion list)
// 2) a search has taken place within the last MIN_SEARCH_INTERVAL
if (DateTime.Now - quickSearchTimeStamp < minimumSearchInterval
|| (view.Suggestions != null && view.Suggestions.Any(i => i.Name == view.SearchText)))
{
return;
}
string searchText = view.SearchText.Trim();
if (searchText.Length < SEARCH_PREFIX_LENGTH)
{
// Do not show suggestions
view.Suggestions = null;
searchAgain = false;
}
// If the prefix has been entered or changed,
// or another search is needed to display the full sublist
else if (searchText.Length == SEARCH_PREFIX_LENGTH
|| searchText.Substring(0, SEARCH_PREFIX_LENGTH) != searchTextPrefix
|| searchAgain)
{
// Record the current time and prefix
quickSearchTimeStamp = DateTime.Now;
searchTextPrefix = searchText.Substring(0, SEARCH_PREFIX_LENGTH);
// Query matches from DB
IList<Instrument> matches = QueryMatches(searchText);
// Update suggestions
view.Suggestions = matches;
// If a large number of results was received, search again on the next chararacter
// This ensures the full match list is presented
searchAgain = matches.Count() > MAX_RESULTS;
}
}
}
(The searchAgain bit is left over from the TextBox implementation, where the AutoCompleteCustomSource wouldn't always show the complete list if it contained too many items.)
Can I get the ComboBox to work as I want it to, providing suggestions as the user types, given my requirement to query those suggestions on TextChanged?
Is there some other combination of controls I should use for a better user experience, e.g. ListBox?
I have looked extensively to find an answer to this question but I only get extremely close. I have a web form that I use to add and edit records. When a record is selected in the gridview, a session variable is set and then used on page load to populate the text fields. If the session variable is not set, the form will be blank and the logic run as a new record. My problem is that I can add a new record successfully - I debugged and checked to make sure the asp controls passed the proper values to the code behind - but I cannot edit a record successfully. For some reason, the code behind file does not retrieve the proper values from the text boxes. Instead, it keeps the original populated values thus defeating the purpose of the edit. I imagine it is a binding issue but I am unsure and have searched upon end. Here is my code behind file:
protected void Page_Load(object sender, EventArgs e)
{
resultOutput.Visible = false;//Output results as to whether or not a record was added successfully is automatically hidden at page load
//Checking to see if session variable has been created
if (Session["editID"] != null)
{
//Create objects to get recipe data
dbCRUD db = new dbCRUD();
Recipe editRecipe = new Recipe();
//Grabbing session ID
var id = Convert.ToInt32(Session["editID"]);
//Call method to retrieve db data
editRecipe = db.SelectRecord(id);
//Populate results to text boxes
recordID.Text = editRecipe.Recipe_ID.ToString();
addName.Text = editRecipe.Name;
addTypeDDL.SelectedValue = editRecipe.Meal;
addDifficultyDDL.SelectedValue = editRecipe.Difficulty;
addCookTime.Text = editRecipe.Cook_Time.ToString();
addDirections.Text = editRecipe.Directions;
//Change Button Text
submitRecord.Text = "Edit Record";
//Change Title Text
addEditTitle.Text = "Edit Recipe";
}
}
protected void submitRecord_Click(object sender, EventArgs e)
{
Recipe recipe = new Recipe();
dbCRUD newRecord = new dbCRUD();
//Variables for execution results
var modified = "";
int returned = 0;
//Creating the recipe Object to pull the values from the form and
//send the recipe object as a parameter to the method containing insert stored procedure
//depending on Add or Edit
//recipe.Recipe_ID = int.Parse(recordID.Text);
recipe.Name = addName.Text.ToString();
recipe.Meal = addTypeDDL.SelectedValue.ToString();
recipe.Difficulty = addDifficultyDDL.SelectedValue.ToString();
recipe.Cook_Time = int.Parse(addCookTime.Text);
recipe.Directions = addDirections.Text.ToString();
//Checking to see if the page is loaded for edit or new addition
if (Session["editID"] != null)
{
recipe.Recipe_ID = Convert.ToInt32(Session["editID"]);
//If recordID exists, recipe will be passed to UpdateRecord method
returned = newRecord.UpdateRecord(recipe);
modified = "has been edited.";
Session.Remove("editID");
}
else
{
//If recordID does not exist, record will be passed to InsertRecord method (new recipe)
returned = newRecord.InsertRecord(recipe);
modified = "added";
}
//Method returns 0 if successful, 1 if sql error, 2 if other error
if (returned == 1)
{
resultOutput.Text = "There was an sql exception";
resultOutput.Visible = true;
}
else if (returned == 2)
{
resultOutput.Text = "There was a non sql exception";
resultOutput.Visible = true;
}
else
{
resultOutput.Text = "\"" + addName.Text + "\" recipe " + modified;
resultOutput.Visible = true;
}
}
Any object passed to my edit method is successful, however, as I mentioned, it does not grab the newly updated text box values.
Did you try checking PostBack property , Your code is loading the data everytime the page is posted back. So when you update the values in the form and hit update button. The Page_Load method is called first and it reloads all the data (replaces your updated values on the form) and then hit the update button event handler. So everytime your old values are being saved.
You may remove the code from page_load method and put it where you are setting the Session["EditId"] value. This will solve your problem.
I would suggest using a static dataset and bind it to the recordsource of the gridview control. Whenever you wanna edit a record update the dataset simultaneously and rebind it to the gridview control....hope that helps:)
I am working on a web app;ication based on asp.net with c#,I have two methods specified below.
public partial class ClerkReception_CreateRecords : System.Web.UI.Page
{
string patid;
protected void ddryear_textchanged(object sender, EventArgs e)
{
string month = "";
if (ddrmonth.SelectedItem.Text == "Jan")
{
month = "01";
}
else if (ddrmonth.SelectedItem.Text == "Feb")
{
month = "02";
}
else if (ddrmonth.SelectedItem.Text == "Mar")
{
month = "03";
}
string year;
year = ddryear.SelectedItem.Text;
string locid = Session["Location"].ToString();
patid = locid + month + year;//Ex:AT112013
myConnection obj = new myConnection();
//string result = obj.fnDisplayManualRecords(year, month, locid);
string result = obj.fnDisplayManualRecords1(patid);
txtlast.Text = result.ToString();
if (ddrmonth.SelectedItem.Text != null || ddryear.SelectedItem.Text != null)
{
txtlast.Visible = true;
lbllast.Visible = true;
BtnProceed.Visible = true;
}
}
This is a method used when a item is selected from dropdownlist,where the patid returns the value.
I need to access the same value of patid inside a another method shown below,Hence I declared the patid as global variable so that I can access the value in any method.But its giving null.How to retieve the vale from one method to another method?
protected void BtnProceed_Click(object sender, EventArgs e)
{
string x = patid;//shows null
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("select top 1(SUBSTRING(patientid,9,4)) as MaxpatientID from Patient_Data where PatientID like '"+patid+"%' order by PatientID desc;", cn))
{
try
{
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
//int Patcount;
if (rdr.Read())
{
int Patcount = int.Parse(rdr["MaxpatientID"].ToString());
// if(Patcount == 0)
}
}
}
catch (Exception ex)
{
// handle errors here
}
}
}
}
}
The global variables are created / intialized between postback in asp.net and they do not retain the values between postback as http is stateless protocol, you need to use ViewState for that. You can read more about ViewState and Stateless protocol over here.
To set value in ViewState
ViewState["patid"] = locid + month + year;//Ex:AT112013;
To get value from ViewState
string patid = ViewState["patid"].ToString();
View State
View state's purpose in life is simple: it's there to persist state
across postbacks. (For an ASP.NET Web page, its state is the property
values of the controls that make up its control hierarchy.) This begs
the question, "What sort of state needs to be persisted?" To answer
that question, let's start by looking at what state doesn't need to be
persisted across postbacks. Recall that in the instantiation stage of
the page life cycle, the control hierarchy is created and those
properties that are specified in the declarative syntax are assigned.
Since these declarative properties are automatically reassigned on
each postback when the control hierarchy is constructed, there's no
need to store these property values in the view state. You can read
more about viewstate here.
Welcome to the world of post backs, each post back recreates the page (class) variables, so you need to save it before post back or it will be gone.
Use a cache object, such as Session to maintain values between post back and page navigation. Session gives you the power to store and retrieve objects across multiple pages in your application, including just one if you are continually posting back to it.
You can use Session, like this:
Storing value in Session:
Session["ValueToKeep"] = "My important information";
Retrieving value from Session:
// Make sure it is in session cache before we try to get it
if(Session["ValueToKeep"] != null)
{
string valueINeed = Session["ValueToKeep"].ToString();
}
Note: All items stored in Session are Objects thus the usage of .ToString() on the Session item. An item is boxed as an object when inserted into Session, but must be unboxed (cast) when retrieved.
You class level variables are re-created on postback. You will need to persist them somewhere that continues across requests.. such as ViewState, Session, etc.
The best way to interact with two methods / functions / event-function in side class is just declaring its accessible modifiers to public and you can call any object of that class after initialize some value to it.
public void ddryear_textchanged(object sender, EventArgs e) {....}
public void BtnProceed_Click(object sender, EventArgs e) {....}
create one variable inside class like string x; and initialize it in constrictor { x="some text "; } this is how code works...
There are many ways to get the value of global parameter,
one way is to define the parameter as static
I've created a custom wizard that generates a windows form through code that lists out some SQL queries for the user. For almost all of the testing of the form and the wizard itself, adding it to a blank project would bring up the form and I could test the button click events and other general form stuff. Most recently I fleshed out the listbox's event listeners and ever since then I get this error:
Googling has lead me to a lot of posts about Ruby, which I'm not using. Other suggestions were reboot and re installation, and those proved unsuccessful. I attempted to comment out the listbox events but that did not keep the error from occuring, however, if it helps here are the events in question:
//-----------Event fired when a listbox object is double-clicked; populate the listbox with the new databases---------
public void dataList_MouseDoubleClick(object sender, EventArgs e)
{
//temp string used to hold the name of the clicked object
string selectedNAME = dataList.SelectedItem.ToString();
firstSEL.TableVar = selectedNAME;
foreach (tempDataVar t in dataVars)
{
if (t.TableVar == firstSEL.TableVar)
{
firstSEL = t;
}
}
string newQ = "SELECT COLUMN_NAME,* FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + firstSEL.TableVar + "' AND TABLE_SCHEMA= '" + firstSEL.SchemaVar + "'";//order by TABLE_NAME'";
results = GetDataSet(bldr.ToString(), newQ);
//listBox1.Items.Clear();
foreach (DataRow row in results.Tables[0].Rows)
{
//foreach (object x in row.ItemArray)
//{
// listBox1.Items.Add(x.ToString());
//}
for (int x = 0; x < row.ItemArray.Length; x++)
{
if (x == 0)
{
colList.Items.Add(row.ItemArray[x]);
}
}
}
dataList.Enabled = false;
}
//-----------------------------Event that fires when the index of the second listbox changes--------------------------
private void colList_SelectedIndexChanged(object sender, EventArgs e)
{
btnYes.Enabled = true;
}
Noobie mistake fixed by a co-worker! I blindly copied and pasted the following code from a "How to make a wizard tutorial":
[ComVisible(true)]
[Guid("20184B81-7C38-4E02-A1E3-8D564EEC2D25"),
ProgId("MyNewWizard.Class1")]
This code needed to be directly above the MyNewWizard class and I accidentally pasted in my custom TempDataVar class in the white space between these lines and the start of the MyNewWizard class. If you're receiving a similar error then I'd suggest testing around the order of some of your attributes/classes!
I have recently switched over from Java/RMI to C# / .net, and am working on my first project using databinding to update records in Oracle. On this first form I'm building, I have a detail view for vehicle records (VIN, year/make/model, license plate number, that sort of thing). The first thing I did in terms of writing to the DB was saving updates:
private void btn_saveDesc_Click(object sender, EventArgs e)
{
bool isSaved = false;
hJA_VEHICLEBindingSource.EndEdit();
DataSet1.HJA_VEHICLEDataTable ch =
(DataSet1.HJA_VEHICLEDataTable)dataSet1.HJA_VEHICLE.GetChanges();
if (ch == null)
{
MessageBox.Show("There are no changes to save.");
}
else
{
Service<TVDDataService.IService1>.Use(svcProxy =>
{
isSaved = svcProxy.SaveVehicles(ch);
});
if (isSaved)
{
// update the vehicle in the local dataset
var modifiedRows = from row in dataSet1.HJA_VEHICLE
where row.RowState == DataRowState.Modified
select row;
foreach (DataRow row in modifiedRows)
{
row.Delete();
}
dataSet1.HJA_VEHICLE.Merge(ch);
dataSet1.HJA_VEHICLE.AcceptChanges();
}
if(isSaved)
{
MessageBox.Show("The record has been saved.");
}
else
{
MessageBox.Show("The record could not be saved.");
}
}
}
That all seemed ok, so I moved on to adding new records. I made a button (I saw online where various people had said it was as good or better to make your own than use a binding navigator) and put this in its handler:
DataRowView drv = (DataRowView)hJA_VEHICLEBindingSource.AddNew();
currVeh_id = nextID(); // generate arbitrary ID for the record
drv["VEH_ID"] = currVeh_id;
drv["GRNTE_ID"] = lastSelectedGranteeID; // just to have an initial value
hJA_VEHICLEBindingSource.Filter = "VEH_ID = " + currVeh_id;
So there (above) I'm putting initial values into some required columns (VEH_ID is the PK). Then I ran the app, entered a value in the textbox for VIN, and went to save (same code as above) and this time GetChanges() returned null.
So I tried this in the "add new" button handler, in place of the first thing:
DataSet1.HJA_VEHICLERow newRow =
(DataSet1.HJA_VEHICLERow)dataSet1.HJA_VEHICLE.NewRow();
currVeh_id = nextID();
newRow.VEH_ID = currVeh_id;
newRow.GRNTE_ID = lastSelectedGranteeID;
dataSet1.HJA_VEHICLE.AddHJA_VEHICLERow(newRow);
hJA_VEHICLEBindingSource.Filter = "VEH_ID = " + currVeh_id;
Now I have something really interesting happening.
- I can successfully enter and save data on any number of new records, until I select an existing record. If I move to an existing record and then add a new record, then when I go to save the new record, the values that were explicitly set in code get written to the DB but data entered into the GUI do not "take" for the new record.
- I can successfully change any number of existing records, until I enter a new record. If I add one or more new records, save, and then try to save changes to an existing record, the call to GetChanges() returns null (so again, apparently it is not "seeing" what's been entered through the GUI).
So in both of these cases, the change from old to new, or new to old, appears to introduce some condition that makes the datatable unaware of what was entered into the GUI. But in changing from old to new it only takes selecting an existing record, whereas with changing from new to old, it only breaks after saving (if I do a new record but then abandon it without saving, I can modify existing records without problems).
I added this into the save handler, just prior to the actual save (in a loop because ch is a datatable, but really the code is set up to where you have to either save or abandon the new record before moving on - thus the loop only executes once):
foreach (DataSet1.HJA_VEHICLERow r in ch)
{
DataRowView drv = (DataRowView)hJA_VEHICLEBindingSource.Current;
MessageBox.Show(drv["VIN_ID"].ToString());
MessageBox.Show(r.VEH_ID + "\n" + r.GRNTE_ID + "\n'"
+ r.VIN_ID + "'");
}
Where VIN_ID is the column to which this particular textbox is bound (I tried this with other fields on the form too, to verify it wasn't just something flaky about that one textbox). The first message box (DataRowView from the binding source) shows the vin that I entered into the textbox. The second message box (row from the table returned by GetChanges()) shows the empty string for VIN_ID, although it has the correct (set through code) values for VEH_ID and GRNTE_ID. The same thing happens if I select a different value for GRNTE_ID using the combo box bound to that column; the row from the datatable still has the value that was set through code, "unaware" of the value selected through the GUI.
Why would the datatable and binding source have different values for the same field? And why would the datatable be able to "see" values entered through the GUI only until the user switches from existing to new, or from new to existing?
Thanks.
Angel:
I'm doing that in my Service:
public bool SaveVehicles(DataSet1.HJA_VEHICLEDataTable vehicles)
{
bool saved = false;
if (vehicles != null && !vehicles.HasErrors)
{
HJA_VEHICLETableAdapter ta = new HJA_VEHICLETableAdapter();
int result = ta.Update(vehicles);
saved = (result > 0);
}
return saved;
}
This is called from this block from my original post:
Service<TVDDataService.IService1>.Use(svcProxy =>
{
isSaved = svcProxy.SaveVehicles(ch);
});
Johannes:
The call to EndEdit() is the second line in the save handler (near the top of my post). Should I be calling it somewhere else as well?
Thanks.
Just to clarify: SaveVehicles cannot be the source of the problem, since the problem is appearing before SaveVehicles is ever called. What condition could cause a discrepancy between the BindingSource and the DataTable after EndEdit() has been called and before anything actually writes to the DB?
You have to update your table adapter after use EndEdit(); also you can update your complete DataSet with the follow snippet :
this.BindingSource1.EndEdit();
this.TableAdapter1.Update(this.DataSet1);
Hopes Helps...
*IF you are using a BindingSource as well:
Just do a simple BindingSource.EndEdit() and your TextBox data will be sent over to the DataTable.
Example:-
_bsHeader.EndEdit();
if (_dsHeader.HasChanges())
{
DataTable dsInsert = _dsHeader.GetChanges(DataRowState.Added).Copy();
_objDal.Insert(dsInsert);
}
Hope this helps anyone who stumbles here.