Why is my LINQ query giving me old data? - c#

I have the following code in an aspx.cs file:
protected void Page_Load(object sender, EventArgs e)
{
epdc = new edu_portalDataContext();
IQueryable<Assignment> _assignmentsList =
from assignment in epdc.Assignments
select assignment;
assignmentsList = _assignmentsList.GetEnumerator();
assignmentsList.MoveNext();
ListOfAssignments.DataSource = epdc.Assignments;
ListOfAssignments.DataBind();
}
Notes, to make it possible for you to understand the code:
Assignments is the name of the database table from which I'm pulling data.
ListOfAssignments is the ID of a Repeater control.
assignmentsList is used in the ListOfAssignments_ItemDataBound method.
Anyway, this is straightforward enough -- instantiate a data context, send it a basic query, get an enumerator, bind some data to a repeater. This part works. The next part is what confuses me.
Later on in the code, I have a click event tied to a Button control. What I want to happen is, the user enters some data in some fields, the user clicks on the button, the program makes a new record with that data, the program sends it off to the database, the database stores the new data, the Repeater (ListOfAssignments) updates with the new database data, and the user sees the new data on the page.
Here's the code in the click event:
Assignment newAssignment = new Assignment
{
//data is entered here
//...
};
epdc.Assignments.InsertOnSubmit(newAssignment);
epdc.SubmitChanges();
But here's what actually happens: when the user clicks the button, everything goes as expected, except the repeater doesn't update with the new data. I did a little debugging, and here's what I found:
assignmentsList doesn't update with the new database data. I looked around in Visual Studio's variable inspector, and the LINQ query doesn't pull in any of the new data. It's as if the user never entered anything at all. Until they refresh the page, that is: when they refresh, the Repeater updates and shows the new data.
Why doesn't the LINQ query give me fresh data on a postback?

Your click event is happening AFTER Page_Load. So the repeater is rebound before the new data is added. Do your databinding in PreRender.

Related

Can you fire off a PostBack in ASP.NET using C#?

From research, the answer to my question seems to be a resounding no.
From Rob de la Cruz's answer here and Jonathan Wood's answer here, it seems that the only way to do it is to use JavaScript. Sadly, I don't have the necessary skill level to implement their solutions and I'm not completely sure it will work for my situation anyway. See what you think:
What I have (using asp.net and C# in VS2019) is a treeview control which:
1.1 At the first level, displays the names of customers.
1.2 Expand a customer node and the next level displays a list of sales order numbers for that customer.
1.3 Expand a sales order node and the third and final level displays a list of the sale items belonging to that particular sales order.
Pretty standard stuff I should imagine. Now, also pretty standard is that, when a node is clicked a procedure will make visible a formview which displays information about that object. When a customer node is clicked it will display the customer formview. When a sales order node is clicked it will display a sales order formview. When a sale item node is clicked... you can probably guess what it displays then.
And this is where things start to go off the rails. When a node is clicked, it's Value property is stored in a variable called _id. This variable is then stored in ViewState. When the PostBack happens, the idea is that the Page_Load event will read the value of _id from ViewState, run the showFormViews() procedure and display the relevant formview. I have it laid out like this:
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["_id"] == null)
{
_id = "";
}
else
{
_id = Convert.ToString(ViewState["_id"]);
}
if (!IsPostBack)
{
fillTreeView;
tv.CollapseAll();
}
showFormViews();
}
and when a node is clicked:
protected void tv_SelectedNodeChanged(Object sender, EventArgs e)
{
// (a) PostBack occurs and Page_Load is run *before* _id is set and stored in ViewState
_id = tv.SelectedNode.Value;
ViewState.Add("_id", _id);
showFormViews();
// (b) would be great to be able to fire off a PostBack programmatically right here!
}
(the .aspx markup is just a TreeView and three FormViews linked to ObjectDataSources)
As I now know from this helpful page:
"The initialisation part of the page lifecycle will execute before the
event handler of the control that caused the post back. Therefore the
code in the page’s Init and Load event handler will execute before the
code in the event handler for the button that the user clicked."
As written at line (a) above, when the treeview node is clicked, the page is posted back and Page_Load is run whilst _id is still null. Because _id is null the showFormViews() procedure hides all of the formviews.
Then the SelectedNodeChanged event fires, _id is set and the showFormViews() procedure sets the relevant formview to visible. But of course, by now all of the controls have been rendered and so... nothing happens.
Being able to somehow fire a PostBack at line (b) would work out wonderfully. Page_Load would fire and run showFormViews() but this time with _id being what it should be.
Various variations at line (b) of:
Server.Transfer("samePage.aspx");
// or
Response.Redirect(Request.RawUrl, false);
don't work because they destroy ViewState (unless someone knows different?) so _id is back to being null again.
So if you can't fire off a PostBack in C# and if I can't work out how to implement the solutions by the two posters above (or even if they will be appropriate in this situation), is there any way I can restructure the page to make this - a fairly common pattern I would imagine - work (and please don't suggest MVC - I tried learning that and still have the nightmares!).
Many thanks in advance,
You can call in your PageLoad the method used to fill the ViewState... Like:
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["_id"] == null)
{
_id = "";
}
else
{
_id = Convert.ToString(ViewState["_id"]);
tv_SelectedNodeChanged(null, null);
}
if (!IsPostBack)
{
fillTreeView;
tv.CollapseAll();
}
}

Sending GridView into edit mode with the use of a separate button

I've used GridView.EditIndex = -1 to do this, however I always have to click the button twice. If data is already present in the gridview, it is removed from the gridview. Why is this?
I have tried:
this.subBindGrid();
protected void subBindGrid()
{
GridView.Columns[7].Visible = true;
GridView.DataSource = <filepath>.Tables[0].DefaultView;
GridView.DataBind();
}
I have also tried:
GridView.DataBind();
on it's own.
Neither of these have made any difference.
Whenever you click on any control on a page. Than request is sent to the server for new page due to stateless nature of http. Every time you click on button you get a new page with DataSource of gridview is empty. to solve this. after GridView.EditIndex = -1.
Bind your Datasource and subBindGrid(); remember this will work only if <filepath>.Tables[0].DefaultView is not null

Accessing dynamically created textboxes text

I have stumbled across a problem with my asp.net form.
Within my form the end user chooses a number of textboxes to be dynamically created, this all works fine with the following code:
protected void txtAmountSubmit_Click(object sender, EventArgs e)
{
int amountOfTasks;
int.TryParse(txtAmountOfTasks.Text, out amountOfTasks);
for (int i = 0; i < amountOfTasks; i++)
{
TextBox txtAddItem = new TextBox();
txtAddItem.ID = "txtAddItem" + i;
txtAddItem.TextMode = TextBoxMode.MultiLine;
questionNine.Controls.Add(txtAddItem);
txtList.Add(txtAddItem.ID);
}
}
However this has also caused a small problem for me, later on in my form on the submit button click, I send the results to the specified person it needs to go to (using smtp email). Again this part is fine, until I am trying to retrieve the text from these dynamically created textboxes.
What I have tried
I have tried using this msdn access server controls ID method however this was not working.
I tried to add these new textboxes to a list, however I was unsure on how to update these textboxes when they have text in them. Therefore my results were returning null because of this.
I have also looked at other questions on SO such as this however they are usually for WPF or winforms, rather than my problem with asp.net (this usually isn't an issue, but I don't need to get the text from every textbox control in my page, just the ones that were dynamically created).
I have also tried changing how I call the code that I hoped would have worked:
string textboxesText = string.Join("\n", txtList.Select(x => x).ToArray());
and then in my concatenated string (email body) I would call:
textboxesText
The problem
As they are dynamically created I am finding it difficult to call them by their id for example: txtExampleID.Text, also as I have to increment the ID's by one each time (so they don't override each other) it has made things a little bit more difficult for me.
I am not asking for a code solution, I would prefer pointers in the right direction as I am still learning.
So to sum it all up: I need to get the text from my dynamically created textboxes to add it to my email body.
The issue is these text boxes need recreated in the Load event of the page, every single time, so that both events and values can be hooked back up and retrieved.
I think the most straight forward approach, in your case, would be to extend idea #1 that you had already tried. Build a List of these controls with enough information to recreate them in Load, but you need to store that List in either ViewState or Session.
ViewState["DynamicControls"] = list;
or
Session["DynamicControls"] = list;
I would use ViewState if you can because it gets destroyed when the user leaves the page.

c# entity , deleting a db record from a drop down list selected value

How do I delete a record from drop down list selected value?
I have populated the drop down list from database and I am having problems to delete it with a delete button. Am I doing the right way? ( Sorry if my codes are messy )
This is how I populate my drop down list:
protected void dropTask()
{
dropListTask.DataSource = daoTask.GetAll();
dropListTask.DataTextField = "TaskName";
dropListTask.DataValueField = "TaskID";
dropListTask.DataBind();
}
This is the delete button :
protected void btnDelete_Click(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Model.task del= new Model.task();
del.TaskID = Convert.ToInt32(dropListTask.SelectedValue);
daoTask.Delete(del);
daoTask.Save();
}
}
I need to add the postback to the btn codes, if I removed it it gives me a error that says;
The object cannot be deleted because it was not found in the ObjectStateManager.
So I put in the postback and the error is gone. Don't know if it is a right way. Please advise me how to to do it correct way.
Thanks in advance.
This: if (!Page.IsPostBack) means that the piece of code will only run on the first run of the page (so NOT when you click the button).
The button click will go back to your ASP page as a post back so eventually you should invert the if, but in the btnDelete_Click method you already know is a postback so you can skip the if altogether.
I believe the error went away because, indeed, you are not executing the code in the if block, so nothing is deleted.
I don't know what daoTask is or how you do persistance in your code but that way of deleting an object from a DB does not sound right... you are creating a new one and assigning it a different ID but the flow should be different:
First find the existing object based on the id, then delete it:
// Don't know if 'Find' is the method you need, you should check based on what
// libraries you are using for saving/loading from DB
Model.task del = daoTask.Find(Convert.ToInt32(dropListTask.SelectedValue));
daoTask.Delete(del);
daoTask.Save();
Googling the error you got should have pointed you in the right direction about the fact that the problem is the DB code, rather than the ASP postback: The object cannot be deleted because it was not found in the ObjectStateManager
UPDATE
Based on the comment you should do something like this:
Model.task del = daoTask.GetTask(dropListTask.SelectedItem.Text);
daoTask.Delete(del);
daoTask.Save();
By the way, I would add a GetTask(int id) method to your daoTask class to be able to find tasks by id rather than name.
It delete the task and fine. But you need to rebind the data to the control dropListTask to take effect the changes in UI.
you can call **protected void dropTask()** for rebind dropdown value after delete

ASP.NET - How to check if one or more field values have been changed

I have a web form where I register a new employee. There're 3 parts in the form: Personal info, Address info, Special Status. But there's only one button for the whole form. When I submit the form all the information is updated to the database. So three Update statements are executed against the database. The methods are UpdatePersonalInfo, UpdateAddressInfo and UpdateSpStatus. Is there a way to check if there's been a change in any field in the certain part and run update method only if it's true. So something like this:
if (There's been any change to the personal data of the employee)
{
UpdatePersonalInfo;
}
if (There's been any change to the address information of the employee)
{
UpdateAddressInfo;
}
Sure I know, I can save all the previous values in a session object in PageLoad and then compare them one by one before running the method. But I thought maybe there's a magic way of doing this more easily.
Not sure that this is a better solution than any of the alternatives you already mentioned, but you could create a default handler to attach to the TextChanged, SelectedIndexChanged, etc events of your controls to keep track of which ones have changed.
List ChangedControls = new List(Of, String);
private void ChangedValue(object sender, System.EventArgs e) {
WebControl cntrl = (WebControl) sender;
ChangedControls.Add(cntrl.ID);
}
Then on your button click scour the ChangedControls list for the relevant controls.

Categories

Resources