Updating ASP.NET label while processing - c#

I have a method thats run on a button click, with 4 labels. What I need to do is update a label after each block of code executes. I've tried threading, updatepanels, etc and can't seem to get anything to work. I thought the timer would work, but it only ticks when you're not inside a method. The code looks something like this:
private void SomeMethod()
{
label1.text = "Processing...";
AnotherMethod();
label1.text = "Done.";
label2.text = "Processing...";
AnotherAnotherMethod();
label2.text = "Done.";
//etc...
}

You have a misunderstanding of how asp.net works. Your server code runs in response to a request from a browser for a complete html page. This is true even when all you really want to do is run some button click code. The entire page must be rebuilt from scratch anyway, even on postbacks. It's just the way web forms are designed.
As soon as the page is rendered to the browser, that instance of your page class is destroyed. On the next postback you'll start from scratch again, with the notable exceptions of the session, viewstate, and the application cache. Even the page's previous DOM instance in the browser is replaced.
So when you set the text property of the label you aren't directly updating anything visually in the browser. All you are doing is updating some temporary storage in your page class. As the last stage of executing your server code, all those temporary variables are used to render the completed html and the response is finally sent to the browser and shown to the user.
That should be enough information to give you an understanding of why your code doesn't behave as expected. It's running all of the code in the method before any of your property changes make their way to the browser. Therefore, the only thing the user sees is the final state of the operation.
Now ajax can complicate things a bit. When using an ajax control you might not be updating the entire page anymore, but the concept still applies: one request is made, and one response is received and used to update the entire context of the request. You can further muddle things if you have a lot of javascript in place to handle the result of the ajax request.
Unfortunately, there's no quick fix for the code you posted. You'll need to think about how this really works and decide how you want your page to flow.

Can you expose the 3 methods to client script and then call them sequentially from your client side code, when method1 finishes the client script would update the ui then call method2, and so on...

Related

PuppeteerSharp - Access a background page, that opens in a new tab, as a regular page

I'm having issues with a program that generates reddit apps with refresh tokens from a discord command.
I've managed to get to a point, where I can generate the application, get all the relevant information, head over to https://not-an-aardvark.github.io/reddit-oauth-helper/ and from there generate the token, which opens a reddit confirmation page in a new window.
I've tried accessing it in various ways and have gone through multiple different methods, until I landed on using Target.PageAsync() to get the page.
For some reason, Puppeteer only sees the page as an iFrame and only gives this link when getting the Url property - https://www.redditmedia.com/gtm/jail?cb=8CqR7FcToPI - which doesn't lead to anywhere but seems to be related to the very first iFrame from what I've gathered in the HTML.
I've ran out of ideas on how to access the page to press quite literally one button and would appreciate any ideas or solutions on how to solve this or how to generate the refresh token without the use of an external website.
Another two hours later and I managed to figure out a solution.
Since PuppeteerSharp was unwilling to recognize the page, I just subscribed to Browser.TargetCreated at the correct moment with a handler that, after immediately unsubscribing, will log the most recent target (in this case, a javascript calling window.open()) and take the sender as the Browser, will then try to get the pages into an array and with a bit of code to ensure that it doesn't break itself, I finally managed a solution, I feel kinda dumb after three days and 12+ hours of work.
For anyone who might run into a similar situation, here's the snippet of code that made it finally work:
// Bla bla bla code to crawl or do whatever on the main page.
// Immediately subscribe to the target created event with the event handler
// that will handle the background page once it has
// been triggered by a button, link, etc.
browser.TargetCreated += TargetCreatedEventHandler;
}
static async void TargetCreatedEventHandler(object sender, TargetChangedArgs e)
{
// Unsubscribe from the event to
// make sure there are no duplicate unnecessary calls that might break the code.
browser.TargetCreated -= TargetCreatedEventHandler;
// Since I know the sender is the Browser object,
// I cast it it to another Browser used inside the event handler.
Browser eventBrowser = (Browser) sender;
// Get all the pages from the event browser
// and assume the first page is background one (for now)
Page[] pages = await eventBrowser.PagesAsync();
Page page = pages[0];
int counter = 0;
// Iterate through the pages, check if they're the page you were just on,
// use an int to help you keep track of of indexes.
// If it isn't the page you were on, assign the Page object the page
// with the current counter index from pages.
// (basically make sure it doesn't break itself with the wrong order).
foreach (var item in pages)
{
if (item.Url != "Main Page URL HERE")
{
page = pages[counter];
break;
}
counter++;
}
// Do whatever you need to do on your background page here
}

ASP.NET UpdatePanel: Make browser "back" button return to *last* version of the page

I have page A and page B. You can do the following things in page A:
Do stuff on page A (e.g., choose an item in a list box), which causes an UpdatePanel in page A to be redrawn with additional information.
Move on to page B. This is done with a Button and Response.Redirect.
Now the problem is as follows:
The user does stuff on page A. Page A is now different from its initial state.
The user moves to page B.
The user hits the back button of the browser.
What happens: Page A in its initial state is shown.
What I would like to happen: Page A in its final state is shown (i.e., with the "correct" item selected in the list box).
I know about ScriptManager.AddHistoryPoint! As far as I can see, it does not solve my problem:
I could call AddHistoryPoint every time something is done on page A. This is bad, because it litters the browser history with lots of entries. (A new entry every time a different list box item is selected.) But that's exactly what I want to avoid by using an UpdatePanel! Of course, if there were a ReplaceLastHistoryPoint method, that would be perfect, but I did not find one...
I tried to call AddHistoryPoint right before Response.Redirect, to save only the last state of page A, but, alas, that doesn't work (no history point is saved). This is not surprising, considering how Response.Redirect works.
Is there some solution I have missed? I'm using .NET 3.5SP1, in case it matters.
This is a bit of an old question, but I'll go ahead and provide the mechanism I use for this. The basic idea is that instead of allowing AddHistoryPoint to manage your name-value pairs, just allow it to manage a key to your NameValueCollection that you keep somewhere else, like in your Session cache. Then as subsequent Ajax requests come in, you never make another call to AddHistoryPoint; instead, you just replace your NameValueCollection with the state of the current request.
The only other bit is to keep track of whether you're on your first Ajax call and need to make that first call to AddHistoryPoint or not.
My code looks something like this:
protected void Page_LoadComplete(object sender, EventArgs e) {
if (!ScriptManager.GetCurrent(this).IsNavigating && (IsCallback || IsInAsyncPostback())) {
var state=new NameValueCollection();
//OnCallbackHistory(state); // this gets state for all interested parties
if (state.Count != 0) {
string key=ViewState["HistoryStateKey"] as string; // empty on first AJAX call
if (string.IsNullOrEmpty(key) || ScriptManager.GetCurrent(this).EnableHistory) {
key=CallbackHistoryKeyRoot+Interlocked.Increment(ref callbackHashKey).ToString();
ViewState["HistoryStateKey"]=key;
ScriptManager.GetCurrent(this).AddHistoryPoint("", key);
}
Session[key]=state;
}
}
}
Instead of calling AddHistoryPoint on the server you could call addHistoryPoint on the client using the Sys.Application class, http://msdn.microsoft.com/en-us/library/vstudio/cc488025(v=vs.90).aspx.
So you'd add a client side click listener to the button which would addHistoryPoint on the client before the button does the post back and redirect.

Interaction of Web User Controls and Structure (Having conceptual difficulties)

In my asp .net C# project I have a page defualt.aspx on which I have placed 2 components.
So in all I have:
1) default.aspx (main page, not doing much code in it)
2) wuc_Lookup.ascx (doing a lot here, grabbing data, setting session, etc)
3) wuc_PageMessages.ascx (has a couple of panels and labels for message output
)
The intent is to use 3) in any page in my application. 1) and 2) are already working. My issue is that the Page_Load sequence is:
1st default Loads
2nd wuc_pageMessage loads
3rd wuc_lookup loads
The problem with this is that The wuc_pageMessage is relevant only after wuc_lookup runs.
My intent was not to put code in Page_Load for the message wuc_pageMessage control because I wanted to be able to call a method to post the message during the component load of wuc_lookup. I do this because only after wuc_lookup do I set the session which I use for the message value.
I actually got values showing up if I put the code in wuc_lookup to manipulate the code-in-front server control (panels and labels) using this.parent.findControl syntax...
But then when I try to rip that code and put it into the code-behind for wuc_pageMessage, and then call the method from the wuc_lookup it has fallen out of scope or context...
So I tried to change this.Parent by passing httpContext.current.handler as casting it as page...that didn't work...then I tried passing Object sender from the calling component...that didn't work either. Neither of them had the Parent property and or it was null which led me to believe that once the wuc_PageMessages.ascx loaded it was a dead deal until a repost happens and that is ugly and something I don't want to do.
I am having some implementation issues and I am not sure what to do. I have been stunk on this for eight hours and Is there just something I am not seeing?
I want to keep away from spagetti code. I don't want to have to scatter code-behind in 3 different files. Theoretically I should only need 2 of these to talk to eachother. i don't want code-behind in default..it's basically just a container. I want to trigger the wuc_pageMessage from wuc_Lookup.ascx without having it be "in" wuc_Lookup.ascx (peer web user controls) I want that to always be a peer relationship. Any advice would be great ...thanks...
Try moving the wuc_PageMessages logic from the page_load to the page_prerender event.
If you are going to use the preRender you would do it on the default.aspx preRender because this event fires after the wuc_lookup. Prerender will not fire on the components for some reason. So yes, this only solves part of the issue. I am not sure how you would get the alreeady loaded component of wuc_PageMessages to get back into scope. If you try to reference components on a component that has already loaded, you will get a null, like they are not there or not in scope anymore... anyone have any ideas?

Asp.net MVC with Ajax history (jquery address), how to load from the URL?

I am using asp.net mvc with ajax navigation. I use jquery address and I can change the address bar to be like "MYPage.Com/#/Url", but how can I invoke my route when the user enters that link?
This has probably been asked before but I could not find it, so please point me to it if you find it.
You need to use the window.onHashChange event of the window element. It is best to use javascript libraries like jquery bbq to handle the hash change.
If you still want to do it without using a library, then on page load you should make a call to the function that handles the onHashChange even.
There is no event for that (at least not the last time I've checked). You need to make a checker function in JS that will run once every 100ms for example (or more often).
var currentHash="";
function CheckHash()
{
if(currentHash!=window.location.hash)
{
currentHash=window.location.hash;
NavigateTo(currentHash); //or whatever code to execute when address behind `#` changes
}
}
CheckHash(); //Initial Run, for fast reaction on load
window.setInterval(CheckHash,100); //schedules the function to run once every 100ms

Updating on-screen element several times in one function

This has got to be easy, but has got me stumped.
How do I change an element on screen several times in one function?
I want to change a label to read something like "starting..." at the beginning of my function, then go away and do some stuff and then change the label to "finished" at the end.
As an illustration why does the following code:
errorMessage.Text = "Three...";
System.Threading.Thread.Sleep(1000);
errorMessage.Text = "Two...";
System.Threading.Thread.Sleep(1000);
errorMessage.Text = "One...";
System.Threading.Thread.Sleep(1000);
errorMessage.Text = "Go!";
System.Threading.Thread.Sleep(1000);
Just pause for 4 seconds and then change the label text to "Go!" rather than counting down?
TIA
Ben
If you want to time a process and put your results out to a label you should use a string in your function instead. Try something like this:
string countDownTimes = "";
countDownTimes += String.Format("One at: {0}, ",DateTime.Now.ToString());
System.Threading.Thread.Sleep(1000);
countDownTimes += String.Format("Two at: {0}, ",DateTime.Now.ToString());
//etc..
errorMessage.Text = countDownTimes;
If your looking to update the UI button in increments then you should look at a javascript solution or async updates.
The reason that your code only updates the screen once is that it is running inside of a single postback. At the end of the postback, HTML is rendered in returned to the browser for display.
Updating the page multiple times during a postback actually isn't easy. But for what you're doing, there is an easier solution. Use JavaScript to change the caption to "Starting..." at the beginning of the request, and then have the method return "Finished."
Because it is a web page, and the final value is what is sent to the browser. All server side code executes and then sends the final values to browser.
Your code is updating the control with the new value on the server, but it won't be seen by the client. To do what you want, you either have to update the control through client side script (javascript), or you have to refresh the page and display the updated value.
Here is a link to the asp.net pages life cycle which is kinda what you are asking about.
http://msdn.microsoft.com/en-us/library/ms178472.aspx
If you notice nothing is sent to the browser until the Render method.
You need to learn about how the web works;
A browser requests a page from the server
The server sends the page (and might do some server-side processing such as ASP.net)
The client shows the page and runs javascripts on the page
Then these javascripts might change the page after it has loaded, but step 2 can't go and change something that's already been sent to the client.
If it's ASP.NET all the code will be executed prior to send the html to the browser so only the last value will be shown. If you want to do that at client side you will have to do some javascript.

Categories

Resources