Greetings,
Might be having a brain fart this morning, but I need a way to execute some JavaScript at the conclusion of an operation taking place inside an ASP .NET Ajax Update Panel. How can this be accomplished?
Thanks,
jason
Updated based on responses:
I was not entirely clear, as both initial answers were correct given what I was asking. In my case I ONLY want the JS to run when a particular event for the control inside the UpdatePanel is executed, sorry for the confusion.
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequest);
function endRequest(sender, args) {
// Executed when ajax request finishes, you could check the sender variable
// in order to identify which update panel fired the request
}
Here's a good article on it. I think this is exactly what you're looking for:
http://blog.jeromeparadis.com/archive/2007/03/01/1501.aspx
Only caveat is that this sample works against any ajax callback so if you have multiple updatepanels it will fire regardless of which one has completed a roundtrip, etc.
Thanks to KevinP and Darin for their answers. I had actually forgotton about the instance request handlers on script manager. Unfortunetly, in my case I would be firing the end_request everytime the person navigated in the calendar control. I take the blame as I was not clear on all requirements. I have upvoted both of their answers. Here is my final solutions.
(Forgive me this is in VB)
Protected Sub mainCalendar_SelectionChanged(ByVal sender As Object, ByVal ev As EventArgs)
Dim dtStart As DateTime = mainCalendar.SelectedDates(0)
Dim dtEnd As DateTime = mainCalendar.SelectedDates(6)
Dim alertString As String = _
String.Format(
"alert('{0}');", dtStart.ToString("d") + " - " + dtEnd.ToString("d")
)
scriptManager.RegisterStartupScript(upCalendar, GetType(String), _
"alert", alertString, True)
End Sub
In this context the alert is only ever displayed on the selection of a week in the calendar, not when the user changes the month or does something else relating to navigation.
Thanks again to both responders for their help
Related
In short, remaining in the HTTP context, I would like the user, after clicking on an order completion button, not to wait for the mails to be sent before being sent back to a "thak you page".
I saw that HostingEnvironment.QueueBackgroundWorkItem could help me with this but there is always the risk of it being killed by IIS recycling.
What is the best solution to do this?
I know the best would be to develop a separate console solution but it wouldn't be worth it for 3/4 emails, alternatively I could consider speeding it up by making them asynchronous?
Protected Sub btnConcludiOrdine_Click(sender As Object, e As System.EventArgs) Handles btnConcludiOrdine.Click
If IsValidOrder(Me._cart, msg) Then
If Me._cart.SaveOrder(Me._user, Me._orderCode, Me._lang) then
'Update quantity in db
Dim mail As New EmailBLL
mail.SendOrderNotice(Me._cart, Me._lang) '2 Mails
mail.SendProductNotice() '2 Mails
End If
Else
Response.Redirect("*Error URL*")
End If
End Sub
The way you approach this is as suggested – start a task, or so called new processor thread.
So, what you would do is break out the code – this even works if code behind is for a web form.
So, the first step is to move out the “slow” parts, or the parts we want to run separate.
The main issue is that to start/launch/want/desire/achieve a brand new processor thread?
The sub call CAN ONLY PASS ONE “parameter” and the sub can only accept one parameter!!!!!
I note in your case that routine needs two values.
However, that “one parameter” can be a array of “many” values, or even a collection or whatever. In our case we pass the two values.
So just keep in mind that what you call can NOT update or “use” the values of controls on the form – the instance of that form will go out of scope.
But we can of course PASS the values you need. This will allow that routine to run 100% independent of the web form.
I also VERY strong suggest that if you DO place the sub in the same web page code behind? You should/can mark that sub as shared. Doing so will allow the compiler to get mad at you and spit out errors if that routine say tries to use or update a control value on the form.
However, it is MUCH better is to place this sub in a separate standard code module out side of the web forms code behind.
Regardless of above, we can now re-write the code we have as this:
If Me._cart.SaveOrder(Me._user, Me._orderCode, Me._lang) then
Dim myInfo(1) as object
myInfo(0) = me.cart
myInfo(1) = me_._lng
Call MyUpdateQ(myInfo)
End If
' bla bla lba
Shared Sub MyUPdateQ(p() as object)
'Update quantity in db
Dim mail As New EmailBLL
mail.SendOrderNotice(p(0),p(1)
mail.SendProductNotice() '2 Mails
End Sub
Ok, so far, we not achieved much, but we re-writing to accept the ONE array is KEY here.
So, now now make sure the above runs/works and is all happy.
Now, because we moved out the "work load" to that one routine, it is now a simple matter to start a thread.
Now, Our above code becomes this:
Protected Sub btnConcludiOrdine_Click(sender As Object, e As System.EventArgs) Handles btnConcludiOrdine.Click
If IsValidOrder(Me._cart, msg) Then
If Me._cart.SaveOrder(Me._user, Me._orderCode, Me._lang) then
Dim myInfo(1) as object
myInfo(0) = me.cart
myInfo(1) = me_._lng
Dim MyThread As New Thread(New ParameterizedThreadStart(AddressOf MyUpdateQ))
MyThread.Start(myInfo)
End If
Else
Response.Redirect("*Error URL*")
End If
End Sub
Shared Sub MyUPdateQ(p() as object)
'Update quantity in db
Dim mail As New EmailBLL
mail.SendOrderNotice(p(0),p(1)
mail.SendProductNotice() '2 Mails
End Sub
That is it. Now when you click your button it will wait ZERO time, since the long running routine is now going to run 100% as a separate thread. And this will also mean that when the user clicks the button - the page will respond instant and post back to user will be done. So if that thread takes 6 seconds, or even 25 seconds, the user will not notice this delay.
Just push your sending mail logic in Task and if you are not interested in result don't await it. c# syntax
Task.Run(() => SendEmail());
I'm trying to get a timer to move between 3 Views in a MultiView control here is the code I'm using:
Protected Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim activeView As String
activeView = MultiView1.GetActiveView().ID
If activeView = "View1" Then
MultiView1.SetActiveView(View2)
End If
If activeView = "View2" Then
MultiView1.SetActiveView(View3)
End If
If activeView = "View3" Then
MultiView1.SetActiveView(View1)
End If
End Sub
On page load I have the MultiView Control set to View1 (MultiView1.SetActiveView(View1))
The page loads correctly and the data (being pulled from an SQL server is visible. After the first tick on timer1 the second view appears again showing the correct data. Then nothing I can see the reload button on the browser going at the timer interval but I never see View3 or a return to View1
Before anyone suggests I had build the If statement as If, ElseIf, EndIf but I broke it out into separate If statements to see if that would help.
It didn't.
I Hope someone can help
Cheers
Have you tried to debug your code with breaks, try to put a break in the If...End If blocks and watch if it is reachable.
You may be having different IDs set for your views, or maybe some cASE mismatching. I will suggest, rather comparing view's ID string, it is safe to compare views index by MultiView1.ActiveViewIndex, this will return only an integer which is lot safer to compare.
Hope it will work.
Sometimes I wonder if I should be let out without a carer.
I found out why the views or label.text changes weren't progressing. I had set the startup info in page_load so even though the timer was firing it was doing a page_load which was defaulting back to the original data.
Sorry for the waste of your time.
I'm off to slowly bang my head against the wall until it doesn't hurt anymore then return to my project.
i have a question about allowing only one pageinstance in all clientsessions. So if a client ask for the unique page and there is already a session with this page. The client which ask for the page should get a messagebox, which say "This page is already in use"
I read about this problem on forums. Many people say "it's impossible to get out if the client have close the browser (including the unique page)".
Is that true about the serverside?
Is there a way to handling this problem?
Is use Asp.net with Vb.net
i hope anyone understand me. My english is bad.
The problem with keeping track of whether the current user is still using the page can be managed by having an UpdatePanel with a Timer which then sets an application variable time every 500ms (or whatever interval you want)
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs)
Application["PageLastUsed"] = DateTime.Now;
End Sub
and redirect users if the page is in use
TimeSpan duration = DateTime.Now - (DateTime)Application["PageLastUsed"];
if (duration.TotalSeconds < 2)
{
Response.Redirect("InUsePage.aspx");
}
See timer info here http://msdn.microsoft.com/en-us/library/cc295400.aspx
I am an absolute beginner on ASP.net (VB.) Please pardon me if the question is too obvious for the experienced members.
I tried to make a simple WebRequest in the async mode in case the target URL takes long to provide the data. In my code below, I just want to see if the callback block (RespCallback) is called correctly every time. If all goes well, lblResult should have the string '123' appended to it every time I click the button which calls the 'GetData' sub.
However, the lblResult only shows 123 after the first click. After the subsequent click, the lblResult only gets appended with '12', as if RespCallback is never called. When I tried to debug this in Visual Studio, the execution actually stepped right into the RespCallback part and the lblResult.Text watch actually shows '123123' but the resulting Web page always shows only '12312'
I am sure I am missing something basic here, but I just don't know what. I was even guessing that it has to do with browser cache (hence the result changes for the second time) but I don't know how to fix that either.
Can someone please help? Thanks in advance.
Jim
Dim myWebRequest As WebRequest
Public Shared allDone As New ManualResetEvent(False)
Private Shared BUFFER_SIZE As Integer = 1024
Public Class RequestState
' This class stores the state of the request
Private Shared BUFFER_SIZE As Integer = 1024
Public requestData As StringBuilder
Public bufferRead() As Byte
Public request As WebRequest
Public response As WebResponse
Public responseStream As Stream
Public Sub New()
bufferRead = New Byte(BUFFER_SIZE) {}
requestData = New StringBuilder("")
request = Nothing
responseStream = Nothing
End Sub ' New
End Class ' RequestState
Public Sub GetData(Sender As Object, Args As System.EventArgs)
lblResult.Text += "1"
myWebRequest = WebRequest.Create(dataURL)
Dim myRequestState As New RequestState()
myRequestState.request = myWebRequest
' Start the asynchronous request.
Dim asyncResult As IAsyncResult = CType(myWebRequest.BeginGetResponse(AddressOf RespCallback, myRequestState), IAsyncResult)
lblResult.Text += "2"
allDone.WaitOne()
End Sub
Private Sub RespCallback(asynchronousResult As IAsyncResult)
lblResult.Text += "3"
allDone.Set()
End Sub
I don't know VB so it's hard to read for me but I'm suspecting GetData is your onClick handler.
First thing that is not right is that you have Shared members. Why your reset event is Shared? It makes all requests use the same object.
Basically Your code with ManualResetEvent won't work because after first allDone.Set(), your object remains set (as long as web application lives). To get "123" every time you should add allDone.Reset() after allDone.WaitOne().
In Your situation web request returns to client before RespCallback is called every time except first call (when your reset event is in non-signaled state).
AutoResetEvent resets automatically. That's why it worked.
But! You can't do this this way. Making your ResetEvent Shared you make all request use the same object. When more than one request will be processed by your application at the same time you will get undetermined behavior.
Remove Shared from your code. Than your code will work (but not asynchronously) without allDone.Reset() and without AutoResetEvent. But it will provide known results (not depending on amount of requests).
About asynchronous call (now that we have code "working"). Well. There is no async request to your web page. allDone.WaitOne() waits until your async webRequest finish. So basically you could just as well do synchronous request.
You need a special pattern for asynchronous web pages. You can read how to do this here.
But i'm not sure it's what you wanted. Do you want your request to be called asynchronously so that it will not use server resources or do you want to display some message to the user (like "Data is being downloaded...") while your web page will remain fully responsible?
If it's the second one you should use AJAX functionality (Like UpdatePanel or using JavaScript directly). You can read about it here.
Couple things to check:
If your label is a fixed width, then it's possible the text is being clipped
If you are using an UpdatePanel, you will need to set its mode to 'Conditional' and call Update() on it in the RespCallback callback method so that the UI gets refreshed with the latest label text value.
I have a long running task that I need to implement on a webpage. What I would like to do is run the task on a separate thread, but have a progress bar on the webpage.
I am struggling to find an easy way of doing this. Here is a very simplified example that I want to do this on. Basically, I want the ResetAll() in a thread, and pool the variable y to update the webpage UI.
Can someone help me?
Protected Sub btnReset_Click(sender As Object, e As System.EventArgs) Handles btnResetLowConductor.Click
ResetAll()
End Sub
Private Sub ResetAll()
Dim y As Integer = 0
While y < x
y += 1
Reset()
lblProgress.Text = y & "/" & x
End While
End Sub
Private Sub Reset()
Threading.Thread.Sleep(200)
End Sub
your lblProgress will not update as long as thread is alive. You will get only final value of y & x i.e when thread is dead. You can store the values of Y & X inside a session variable.
Private Sub ResetAll()
Dim y As Integer = 0
While y < x
y += 1
Reset()
Session("CurrentStatus") = y & "/" & x
End While
End Sub
From Your UI you will fire an asynchronous event using PageMethod i.e
function GetCurrentThreadStatus()
{
PageMethods.GetThreadStatus(function(status){
// success
$("span[id*='lblProgress']").text(status);
});
}
Code Behind : C#
[WebMethod]
public static string GetThreadStatus()
{
return (string)Session["CurrentStatus"];
}
As this is a website, you will probably need to use some sort of ajax method to call back to the server periodically. Here is the basic flow of your program as far as I can see it:
User makes initial call
Spin up new thread to run process and return with a 0% status
Periodically, make a call to the web server via ajax (A GetStatus call that will return the percentage of completion)
If the call is complete, update/refresh the page appropriately
If the call is not complete, then use the returned status
Now, I am not as sure about the details given that this is a web page, but you could try to store the status in the session variable (which may or may not be possible once you have already returned) periodically, and then the GetStatus will just read the most current status. If session does not work, then you will need to persist the status another way (db, file, etc).
Just be careful on how often you store the status. Too often and you slow your process down, and too little and you do not give an accurate representation of the status.
Last, if you can upgrade to .NET 4.0, then this becomes even more trivial using the TPL (Task Parallel Library)
You are confused about how web pages work.
Once the thread is fired and you write the response to the client, you won't be able to continue updating the page as the Thread progresses.
One way to do this sort of thing is using Ajax. Ulhas already showed you a way top do this; all you need to do is have that javascript function he wrote call itself until you get a 100% completion. You can do that using a timer.
Okay, with the help of various websites, I managed to do this.
Here is a sample project. Please let me know if there are any problems with this. I'm no expert, so I would like some feedback!
http://www.mediafire.com/?7vn16vp78rave6a