ASP.NET Ajax Show UpdateProgress control for minimum amount of time - asp.net

Sometimes my ajax request is so fast that the user does not realize a ajax call was made. So I would like to force the UpdateProgress control to display for a minimum about of time, even if the ajax request has finsihed.
For example:
John browses the site and the ajax call takes 2 seconds to complete. I only want the UpdateProgress control to display for those 2 seconds.
Mary also browses the site but the ajax call takes > 0.5 seconds. So I want to display the UpdateProgress control for at least 1 full second.
Does anybody have any ideas on how to do this?
Edit
I have discovered that the AjaxLoadingPanel control offered by Telerik has this ability. It has a property called MinDisplayTime that does this very thing. It would be nice to know how to do this using the standard (Free) asp.net ajax controls.
Thanks

I had the same problem working on an intranet site where the UpdatePanel contents changed so quickly that I couldn't tell if an update had happened without debugging, or checking the database.
The way I tackled this problem was to let the UpdatePanel do its thing as before, but use an UpdatePanelAnimationExtender to briefly flash a change of background colour, for example, before fading back to normal, giving the user the impression that an action has happened. If this happens quickly, say 0.3 of a second, and an appropriate 'action' colour is chosen, this can be very effective.
<ajaxToolkit:UpdatePanelAnimationExtender ID="myUpdatePanelExtender" runat="server" TargetControlID="myUpdatePanel">
<Animations>
<OnUpdating> ... </OnUpdating>
<OnUpdated> ... </OnUpdated>
</Animations>
</ajaxToolkit:UpdatePanelAnimationExtender>
You'll need to get the AJAX Control Toolkit, but if you're doing Asp.Net AJAX work, you'll be better off having it, if you don't already.
For what to place within the <OnUpdating> tag etc., see the Asp.Net Ajax Control Toolkit site page 'Using Animations'.

protected void Button1_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(3000);
Label1.Text = DateTime.Now.ToString();
}
http://www.asp.net/Ajax/Documentation/Live/tutorials/ProgrammingUpdateProgress.aspx

you could work around the latter by keeping track of the time your server side code takes to execute (or perhaps even better by measuring the ajax execution time, but that's more tricky)
the idea is this
long startTime = System.DateTime.Now.Ticks;
//this process can take some time, especially when executed for the first time
//it gets data and binds it to a control
FetchData();
//if this takes not enough time, add an extra second to allow the UpdateProgress to display
if (TimeSpan.FromTicks(DateTime.Now.Ticks - startTime).TotalSeconds < 1)
System.Threading.Thread.Sleep(1000);

Related

ASP.NET conditional yes/no messagebox

I have an asp:Button that fires a code behind function on the OnClick event. In that OnClick event several things happen, and among those things I do a check in the database for if I need to ask the user a yes or no question. For that I need a message box. First I did it like this:
protected void MyButton_Onclick(object sender, EventArgs e)
{
// lots of stuff happening
bool iNeedToAskTheUser = INeedToAskTheUser(stuff);
if (iNeedToAskTheUser)
{
DialogResult result = MessageBox.Show("Do you want to fix all objects?", "Fix objects", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes) // do stuff
}
// some other stuff
}
This works fine locally but not when deployed, so I figure I would need to use ScriptManager.RegisterStartupScript instead. I could just add javascript on the ASPX page that fires up a dialog and saves the response in a hidden control that I can then look at, but I don't want to fire up the dialog unless I have to, which I check for before I do the DialogResult in the code above. So I can't do that immediately when the user clicks the button.
Is there any way I can use ScriptManager.RegisterStartupScript in "the middle" of my _OnClick code so that I can choose whether or not to actually show the button, and then also know if the user clicked yes or no, (preferably) without doing a postback?
I've been thinking and testing two different solutions:
Use ScriptManager.RegisterStartupScript in code behind to fire a JavaScript confirm function on the ASPX page. The JavaScript function would set a value in a hidden control depending on if the user answered yes or no and then my code behind stuff would check the value of that hidden field and act upon that. The problem with that is that once ScriptManager.RegisterStartupScript fires it doesn't wait for the JavaScript function to "finish", ie wait for the user to reply to the confirm(). So the value in the hidden control will always be empty because the code behind gets to the check of that control before the user has a chance to respond to the confirm(). So that's a no go.
Use ScriptManager.RegisterStartupScript in code behind to open up a new ASPX page that asks the user the question and then does all the work in response to the user's answer in that page. The problem then is to pass the object that the new ASPX page needs to do work on in response to the user's response.
I'm sure there are great solutions using Ajax or jQuery but this is a fairly simple function that shouldn't take too long to develop, so that is kind of out of scope for this.
Instead I'll go with a solution where I know what the user will respond to the question before they click the button. (While silently muttering under my breath: "It's 2019 and there's no good way to fire up a yes/no dialog from code behind in a .Net web project...". I need to get back to not working with web).

SP2010 - httpcontext.response.write() not working for LinkButton's onClick event

probably a simple oversight I've missed (though I vaguely recall some obscure blogpost about the inner workings of Response.Write not working as expected in some situations but I don't remember if this is one of them):
The situation is, I have a Link Button on a control running in SP2010, and if I don't use HttpContext.Response.Write(), everything works as expected (ie I can change the .Text value for a Label). However, if I call Context.Response.Write(), while I can debug and step through the code, nothing seems to happen any more (nothing is written back and changes to other controls do not appear). It's being run on an application page in _layouts, appearing in a modal dialog.
(basically, I'm trying to do this - http://acveer.wordpress.com/2011/01/25/using-the-sharepoint-2010-modal-dialog/ but it doesn't work. EDIT: If I change it to a asp:Button, it still doesn't work)
Here's some code if you're interested:
.aspx:
# Page Language="C#" AutoEventWireup="true" ...
<asp:LinkButton CssClass="button remove" runat="server" OnClick="remove_Click" Text="Remove" ID="remove"></asp:LinkButton>
.aspx.cs:
public void remove_Click(object sender, EventArgs e)
{
....
//if successful
HttpContext context = HttpContext.Current;
if (HttpContext.Current.Request.QueryString["IsDlg"] != null)
{
testControl.Text = "test code";
//doesn't work, and prevents line above from working
Context.Response.Write("<script type='text/javascript'>alert('hi!');</script>");
Context.Response.Flush();
Context.Response.End();
// context.Response.Write("<script type='text/javascript'>window.frameElement.commitPopup()</script>");
// context.Response.Flush();
// context.Response.End();
}
}
Anyone come across something similar?
EDIT: some more interesting pieces that may help,
The button itself lies within an UpdatePanel
I do have a AsyncPostbackTrigger assigned
Using Response.Write from Web Forms code behind is problematic at best. As a rule of the thumb: never ever use Response.Write from a Web Forms page or user control.
The reason Response.Write is problematic, is because it is not part of the page's control tree, and rendering infrastructure. This means that when used within events in it will output the text outside of the normal page flow, and usually outside of the proper HTML page structure.
This is also why things go awry when you're using them in combination with UpdatePanels. As UpdatePanels are specifically designed to replace parts from a page, the infrastructure needs to know which parts. A Response.Write happens completely outside of this, and there's no real way of knowing where to render it. At best, the ScriptManager will perform a Response.Clear to wipe out your Response.Writes, at worst you'll break the UpdatePanel protocol body and you'll get a JavaScript error.
To top things off, any literal <script> tag will be ignored when you're performing a partial page update, as the browser's innerHTML feature used to fill in the HTML fragments sent by the server does not execute <script> tags.
Now, with all this theory out of the way -- is there no way to execute a piece of JavaScript code through an UpdatePanel? It turns out there is, and it's a lot cleaner than just executing a Response.Write: ScriptManager.RegisterClientScriptBlock and ScriptManager.RegisterStartupScript. For example:
ScriptManager.RegisterClientScriptBlock(
theButton, // control or UpdatePanel that will be rendered
typeof(YourPage), "UniqueKey", // makes your script uniquely identifiable
"alert('Testing!');", true);
The important part is the first argument: now the ScriptManager will know when to execute your script. If you register it on a control that is not updated on a partial page refresh, your script will not execute. But if the UpdatePanel containing the control is refreshed, your script that is hooked up to it will also execute. And that's usually exactly what you want.
If you always want to execute your script, regardless of which panel updates, you'd call
ScriptManager.RegisterClientScriptBlock(Page, ... );
#Ruben provided a very good answer, but I felt I could add useful content that doesn't fit in a comment.
There are a few occasions in SharePoint where you use a Response.Write - namely when dealing with webparts that are displayed within a SharePoint Modal popup and you want to do something cute with the callback when using window.frameElement.commitPopup().
The fact that you are using Response.Write within an update panel is actually part of your issue. When a postback that was generated with an update panel returns, the response is formatted with UpdatePanelId|Response Content where UpdatePanelId is the div associated with the update panel and Response Content is the new inner HTML of the div. When you use response.write, that format is lost, therefore the ScriptManager has no idea what to do with the response and should ignore it as erroneous. #Ruben provided you a method of registering scripts within an UpdatePanel.
Context.Response... should have a lower case context
ie:
context.Response.Flush()
etc
or am I missing the point?

Can I get away with this or is it just too crude and unpractical?

I spent the whole of last night searching for a free AspNet web chat control that I could simply drag into my website. Well the search was in vain as I could not find a control that matched my needs i.e List of users, 1 to 1 chat, Ability to kick out users..
In the end I decided to create my own control from scractch. Although it works well on my machine Im concerned that It maybe a little crude and unpractical on a shared hosting enviroment.
Basically this is what I did :
Created an sql database that stores the chat messages.
Wrote the stored procedures and and included a statement that clears old messages
Then the 'crude' part :
Dragged an update panel and timer control on my page
Dragged a Repeater databound to the chat messages table inside the update panel
Dragged another update panel and inside it put a textbox and a button
Configured the timer control to tick every 5 seconds.
..and then I made it all work like this
In the timer tick event I 'refreshed' the messages display by invoking Databind() on my repeater i.e
protected void Timer1_Tick(object sender, EventArgs e)
{
MyRepeater.DataBind();
}
Then in my send button click event
protected void btnSend_Click(object sender, EventArgs e)
{
MyDataLayer.InsertMessage(Message, Sender, CurrTime);
}
Well It works well on my machine and Ive got the other functionalities(users list, kick out user..) to work by simply creating more tables.
But like I said it seems a little crude to me. so I need a proffesional opinion. Should I run with this or try another Approach ?
I'm not sure why you think it is crude - I would expect any other ASP.NET chat control to be developed in exactly the same fashion using client-side polling. As an alternative to using Update panels however, I would recommend writing the client-side AJAX functionality using JQuery (or some other Javascript framework) - the ASP.NET Update panel is really just a standard ASP.NET postback using a rendering trick so the screen doesn't have to be refreshed.
In regards to running with what you've got, if you've gone as far as you have already, I would continue on. It will be a great learning exercise on the requirements for your chat client even if you decide to replace it with something else down the track.

How to prevent repeated postbacks from confusing my business layer

I have a web application (ASP.Net 3.5) with a conventional 3 layer design. If the user clicks a button a postback happens, some middle and data layer code runs, and the screen is refreshed. If the user clicks the button multiple times before the first postback is completed my logic gets confused and the app can end up in an invalid state.
What are the best ways to prevent this?
I can use javascript to disable the button but this just hides the problem. How do I build my business and data layers to handle this?
The three most popular methods (which are often used in tandem) are:
Disable submit buttons once clicked/pressed;
Use POST+REDIRECT+GET to avoid back button issues; and
Replace history in the browser so you can't go back (but this should be used sparingly and with good reason).
If I was to be brutally honest, I would say that it sounds like you're the one confused about web postbacks, not your application (that's if you're the one who wrote it). ;-)
That said, in addition to other suggestions, what I would do in this case is place a "token" in hidden field in the form - like a GUID - that is posted back. Use this to track the work being done and only allow it to be used once. E.g. when posted back, place it in session storage. Each time a postback is performed check the session first for this token, and if it is there then do nothing. If it's NOT there, store it in session and do the work. When the session ends, tokens are thrown away automagically. Easy. Much better than some convoluted database token.
Oisin
Do disable submit button once clicked. This will prevent accidental double-click or more
I usually redirect to a different URL after postback to avoid accidental/intentional page refresh.
Finally in your DB insert method, check for identical data inserted within certain time frame (probably in seconds) before doing the insert. If duplicate data is found inserted within just seconds (or minutes. whatever makes most sense in your situation), show warning message and have user hit submit again if user feels it is not error. (This method makes most sense when you have user account and user is submitting data when logged in, so duplicate data check is done for the user.)
Check out this ASP.NET AJAX control called PostBack Ritalin from a fellow SO'r Dave Ward.
I have solved the problem writing a javascript disabling the click function button:
MyButton.Attributes.Add("onclick",
"javascript:this.onclick=function(){return false;};");
We have all seen the websites that disable "submit" buttons when you click on them. This is often done to prevent users from clicking the button multiple times.
Normally this is accomplished using an 'onclick' JavaScript event to disable the button. In ASP.NET, each server side item already has a onclick event handler which calls the server back for event processing.
To accomplish the same thing in ASP.NET, you could easily do:
btnSubmit.Attributes.Add("onclick", "this.disabled=true;" + GetPostBackEventReference(btnSubmit).ToString());
Where 'btnSubmit' is the name of the button in question. What happens here is we create an onclick event that does two things. Firstly, it disables the button in the users browser. The second thing it does is submit the normal postback event to the server.
Even i got the Same Problem I have resolved like Below.
After uploading a File If you Redirect to same page or some other page in your project this problem will be avoided.
For Example:
In My ASPX
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm.aspx.cs" Inherits="WebApplication.WebForm" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
</div>
</form>
</body>
</html>
Even i got the Same Problem I have resolved like Below.
After uploading the File If you Redirect to same page or some other page in your project. After Redirection Response will not be there once you redirected.
In My ASPX
In My Code Behind
public partial class WebForm : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
string path = Server.MapPath("~");
path = path + FileUpload1.FileName;
FileUpload1.SaveAs(path);
Response.Redirect("WebForm.aspx"); // Responce will be cleared. This Redirection will do the Trick
//Put the debugger and check it will work
}
}
Here, to show the success and error messages try to use sessions.

How do you call a Javascript function from an ASPX control event?

How do you call a Javascript function from an ASPX control event?
Specifically, I want to call the function from the SelectedIndexChanged event of a DropDownList.
I get a little nervous whenever I see this kind of question, because nine times out of ten it means the asker doesn't really understand what's going on.
When your SelectedIndexChanged event fires on the server, it fires as part of a full postback. That means that for that code to run, the entire rest of your page's load code also had to run.
More than that, the code runs as the result of a new http request from the browser. As far as the browser is concerned, an entirely new page is coming back in the result. The old page, and the old DOM, are discarded. So at the time your SelectedIndexChanged event code is running, the javascript function you want to call doesn't even exist in the browser.
So what to do instead? You have a few options:
Change the page so the control doesn't post back to the server at all. Detect the change entirely in javascript at the client. This is my preferred option because it avoids odd onload scripts in the browser page and it saves work for your server. The down side is that it makes your page dependent on javascript, but that's not really a big deal because if javascript is disabled this was doomed from the beginning.
Set your desired javascript to run onload in the SelectedIndexChanged event using the ClientScript.SetStartupScript().
Apply the expected results of your javascript to the server-model of the page. This has the advantage of working even when javascript is turned off (accessibility), but at the cost of doing much more work on the server, spending more time reasoning about the logical state of your page, and possibly needing to duplicate client-side and server-side logic. Also, this event depends on javascript anyway: if javascript is disabled it won't fire.
Some combination of the first and third options are also possible, such that it uses javascript locally if available, but posts back to the server if not. Personally I'd like to see better, more intuitive, support for that built into ASP.Net. But again: I'm talking about the general case. This specific event requires javascript to work at all.
As Muerte said you have to just put the javascript, or a call to it on the page from the code behind. Personally I use this:
ClientScript.RegisterClientScriptBlock("customscript", "<script>simple script here</script>")
Of you can call the function if you already have a more complex one on the page instead of the stuff I have.
You can't do it directly from an event, because ASPX control event is server side.
What you can do is emit a Javascript in the ASPX event which will call the JavaScript function when the page reloads.
For example, if in your ASPX page you have a Javascript function called "DoSomething()", in you ASPX control event, add the following:
protected void btnSubmit_Click(object sender, EventArgs e)
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "myEvent", "DoSomething()", true);
}
The last boolean parameter defines that tags are added automatically.
In the code behind, attach some markup to the server side control via its attributes collection. This assumes that the function is already in a client script file that is already available to the page.
MyServerDDLControl.Attributes.Add("SelectedIndexChanged", "MyClientSideFunction();");

Resources