Wednesday, March 21, 2012

Delaying Content Load using Timer and UpdatePanel

I've created a custom template control that I'm trying to use to delay content loading on a page for long running controls.

Here:

1public sealed class DelayedContentLoader : WebControl, INamingContainer
2 {
3private MultiView mvContent =new MultiView();
45private int interval = 10000;
6public int Interval
7 {
8get {return interval; }
9set { interval =value; }
10 }
1112public delegate bool LoadContentHandler();
13public LoadContentHandler OnLoadContent;
1415private ITemplate loadingTemplate;
16 [TemplateContainer(typeof(LoadingView))]
17public ITemplate LoadingTemplate
18 {
19get {return loadingTemplate; }
20set { loadingTemplate =value; }
21 }
2223private ITemplate loadFailedTemplate;
24 [TemplateContainer(typeof(LoadFailedView))]
25public ITemplate LoadFailedTemplate
26 {
27get {return loadFailedTemplate; }
28set { loadFailedTemplate =value; }
29 }
3031private ITemplate contentTemplate;
32 [TemplateContainer(typeof(ContentView))]
33public ITemplate ContentTemplate
34 {
35get {return contentTemplate; }
36set { contentTemplate =value; }
37 }
3839protected override void OnInit(EventArgs e)
40 {
41if (loadingTemplate !=null)
42 {
43 LoadingView loadingViewContainer =new LoadingView();
44 loadingTemplate.InstantiateIn(loadingViewContainer);
45 mvContent.Views.Add(loadingViewContainer);
46 }
4748if (contentTemplate !=null)
49 {
50 ContentView contentViewContainer =new ContentView();
51 contentTemplate.InstantiateIn(contentViewContainer);
52 mvContent.Views.Add(contentViewContainer);
53 }
54else
55 throw new Exception("A Content Template must be specified.");
5657if (loadFailedTemplate !=null)
58 {
59 LoadFailedView loadFailedViewContainer =new LoadFailedView();
60 loadFailedTemplate.InstantiateIn(loadFailedViewContainer);
61 mvContent.Views.Add(loadFailedViewContainer);
62 }
63 }
6465protected override void OnLoad(EventArgs e)
66 {
67 UpdatePanel updatePanel =new UpdatePanel();
68 updatePanel.UpdateMode = UpdatePanelUpdateMode.Always;
6970 mvContent.ActiveViewIndex = 0;
7172 updatePanel.ContentTemplateContainer.Controls.Add(mvContent);
7374 Timer timer =new Timer();
75 timer.ID ="timerDelayedContentLoader";
76 timer.Interval = interval;
77 timer.Tick +=new EventHandler(timer_Tick);
7879 updatePanel.ContentTemplateContainer.Controls.Add(timer);
8081 Controls.Add(updatePanel);
82 }
8384public override Control FindControl(string id)
85 {
86 Control ctrl = mvContent.Views[1].FindControl(id);
87if (ctrl !=null)
88return ctrl;
8990 ctrl = mvContent.Views[2].FindControl(id);
91if (ctrl !=null)
92return ctrl;
9394 ctrl = mvContent.Views[0].FindControl(id);
9596return ctrl;
97 }
9899private void timer_Tick(object sender, EventArgs e)
100 {
101bool loadedContentSuccessfully =false;
102if (OnLoadContent !=null)
103 loadedContentSuccessfully = OnLoadContent();
104105// Stop the timer.106 Timer timer = FindControl("timerDelayedContentLoader")as Timer;
107if (timer !=null)
108 timer.Enabled =false;
109110int visiblePlh = loadedContentSuccessfully ? 1 : 2;
111 mvContent.ActiveViewIndex = visiblePlh;
112 }
113 }

The control does work, but once the first 'panel' loads I'm getting this error:

Error: Sys.ScriptLoadFailedException: The script 'http://localhost:2059/WebResource.axd?d=2969z1Qx3dbsV5nCF1BRcXhpF5ub86-cDZ-FaGYdZEBQbKzZVJb7tl6DB7CRlXIMyp8MDajf0oi_5PQ_Zb35Pg2&t=633181289164114804' failed to load. Check for:
Inaccessible path.
Script errors. (IE) Enable 'Display a notification about every script error' under advanced settings.
Missing call to Sys.Application.notifyScriptLoaded().
Source File: http://localhost:2059/ScriptResource.axd?d=w7roB_KjU8DhSirRDxfFxPRhP-DUqImf_4Nd1a5Co3kx1o511QAFqGXxMtkfZR8UkArHbaLDYRdK8lHjJK-ARWQArhEXy5Ydco_GHuMUgH41&t=633120912402558276
Line: 3311

The error kills all of the JavaScript on the page - others delayed content loaders stop loading and all other AJAX stuff ceases to work. The line that is referenced is this line #10 below:

// MicrosoftAjax.js
// Microsoft AJAX Framework.
1function Sys$_ScriptLoader$_raiseError(multipleCallbacks) {
2 var callback = this._scriptLoadFailedCallback;
3 var scriptElement = this._currentTask.get_scriptElement();
4 this._stopLoading();
5
6 if(callback) {
7 callback(this, scriptElement, multipleCallbacks);
8 }
9 else {
10throw Sys._ScriptLoader._errorScriptLoadFailed(scriptElement.src, multipleCallbacks);
11 }
12 }

Is there anything that can be done here? By the way, this control is inside of a Web Part. If I remove all the Web Part stuff, I don't get the error but only one of my delayed content loading controls finishes loading.

Any help would be much appreciated.

Thanks!

Has anyone tried to do this?


Hi

Ok,Just do it like this:

<%@. Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
protected void Button1_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(3000);
TextBox1.Text = DateTime.Now.ToString();
}
</script>

<script type="text/javascript">
function delayLoad()
{
document.getElementById("<%= Button1.ClientID %>").click();
document.getElementById("<%= UpdateProgress1.ClientID %>").style.display = "block";
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body onload="setTimeout('delayLoad()',3000)">
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<div visible="true"><asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /></div>
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1">
<ProgressTemplate>
Waiting...........
</ProgressTemplate>
</asp:UpdateProgress>
</div>
</form>
</body>
</html>

Thanks:)


How is that the same as what I was trying to do? Unless you're saying I need to have my update panel's UpdateMode set to conditional. Are you?


Hi,

In my code,I delay by 3 second to load the content.

It's the same as following code:

<%@. Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
protected void Button1_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(3000);
TextBox1.Text = DateTime.Now.ToString();
}

protected void Timer1_Tick(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(3000);
TextBox1.Text = DateTime.Now.ToString();
Timer1.Enabled = false;
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<div visible="true">
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /></div>
<asp:Timer ID="Timer1" runat="server" Interval="3000" OnTick="Timer1_Tick">
</asp:Timer>
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1">
<ProgressTemplate>
Waiting...........
</ProgressTemplate>
</asp:UpdateProgress>
</div>
</form>
</body>
</html>

A timer for an updatepanel.we can do it.

I know you just want to creat a contorl to include a updatepanel and a timer,I'll do it for you later.


OK

I have done it for you now.

bur I 'm using webcontrol rather than server control,I think it is more simple:)

The code :

The page:

<%@. Page Language="C#" %>

<%@. Register src="http://pics.10026.com/?src=WebUserControl5.ascx" TagName="WebUserControl5" TagPrefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
protected bool WebUserControl5_1_LoadContent(object sender, EventArgs e)
{
try
{
((WebUserControl5)sender).myContent = "OK..........";
}
catch
{
return false;
}
return true;
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div>
<uc1:WebUserControl5 ID="WebUserControl5_1" runat="server" OnLoadContent="WebUserControl5_1_LoadContent" />
</div>
<div>
<uc1:WebUserControl5 ID="WebUserControl5_2" runat="server" OnLoadContent="WebUserControl5_1_LoadContent" />
</div>
<div>
<uc1:WebUserControl5 ID="WebUserControl5_3" runat="server" OnLoadContent="WebUserControl5_1_LoadContent" />
</div>
<div>
<uc1:WebUserControl5 ID="WebUserControl5_4" runat="server" OnLoadContent="WebUserControl5_1_LoadContent" />
</div>
</form>
</body>
</html>

The control:

<%@. Control Language="C#" ClassName="WebUserControl5" %>

<script runat="server">
protected void Timer1_Tick(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(3000);
TextBox1.Text = DateTime.Now.ToString();
bool loadedContentSuccessfully = false;
if (LoadContent != null)
loadedContentSuccessfully = LoadContent(this,e);

// Stop the timer.
Timer1.Enabled = false;

int visiblePlh = loadedContentSuccessfully ? 1 : 2;
MultiView1.ActiveViewIndex = visiblePlh;
}

public delegate bool LoadContentHandler(object sender, EventArgs e);
public event LoadContentHandler LoadContent;
public string myContent
{
set
{
TextBox2.Text = value;
}
}
</script>

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Timer ID="Timer1" runat="server" Interval="3000" OnTick="Timer1_Tick">
</asp:Timer>
<asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
<asp:View ID="LoadingView" runat="server">
Loading...........</asp:View>
<asp:View ID="ContentView" runat="server">
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox></asp:View>
<asp:View ID="LoadFailedView" runat="server">
Failed...........</asp:View>
</asp:MultiView>
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1">
<ProgressTemplate>
Waiting...........
</ProgressTemplate>
</asp:UpdateProgress>

Works cool.....:)

Thanks


Not exactly what I was looking for since I want to build something that's a bit more re-usable than a simple ASCX. Another issue I found was that if I had two instances of the same templated control, say one names 'ctrl1' and the other named 'ctrl2' the timer would just keep updating one or the other like this...

page loads

--ctrl 1 loaded after delayed

--ctrl2 loaded after delayed (ctrl1's content hidden)

--ctrl1 loaded after delayed (ctrl2's content hidden)

--and so on

Very strange.


Delayed content loading is BRILLIANT!....IF you arent delaying an async callback such as a databind. What if you would like to load the graphical content FIRST and then populate a combobox with its records as the delayed content - The browser freezes until the databind is complete! Thats fine if your only VIEWING the page but what if the user would like to start entering input whilst waiting for a Suburb Dropdown to populate....


Hi Delorenzo,

Im also trying for the same. Im trying to delay content loading using ajax controls in Custom control. I have no Idea how to do it, if u got the solution for this problem then plz let me knw.

Thanks in Advance,

Rajak Shaik.


I couldn't get this to work exactly as I wanted it to, so I scrapped it and switched to a solution using JavaScript and Web Services with Prototype and Scriptaculous (for my animation). The solution works great!



Hi Delorenzo,

Thanks for replying. Can u plz tell me how it can be done using Javascript and Webservices, if possible with code.

Thanks in Advance,

Thanks & Regards,

Rajak Shaik.


Another question:

Can I do something like this below? I'd like to update the time as a process is running. However, the time on the edit box only changes (or updates) on the last one. I've tried UpdatePanel1.Update() as well and this doesn't seem to get the refresh to happen either.

protected void Timer1_Tick(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(3000);
TextBox1.Text = DateTime.Now.ToString();
System.Threading.Thread.Sleep(3000);
TextBox1.Text = DateTime.Now.ToString();
System.Threading.Thread.Sleep(3000);
TextBox1.Text = DateTime.Now.ToString();
System.Threading.Thread.Sleep(3000);
TextBox1.Text = DateTime.Now.ToString();
Timer1.Enabled = false;
}

Thanks,

Gary


Hi Gary...

I am a little unclear on what you are trying to achieve. Did you want to show the amount of time that a process takes to complete? or would you just like to show the current time and refresh it every 3 seconds?

Perhaps set the timer to 3000 and then:

protected void Timer1_Tick(object sender, EventArgs e)
{
TextBox1.Text = DateTime.Now.ToString();

Updatepanel.update

}

------
Codey


Well- not exactly so let me ask my real question. Smile I hate to get a little off the posting subject, but hopefully it's helpful.

Inside the timer I'd like to run a loop and when each loop is done then I'd like to update the date in the text box. Actually I don't really want to use a timer either, but if I can make it work that way that would be ok too. It only seems to update the text box at the end and doesn't want to update it after each loop.

protected void Timer1_Tick(object sender, EventArgs e)
{

for (int i = 0; i < 10; i++)

{

CallProcess(i);

TextBox1.Text =DateTime.Now.ToString();

UpdatePanel1.Update();

}

Thanks!!

Gary


The Update wont occur until the postback is complete, therefore the final value that you assign the textbox will be the value that is displayed.

Even though you are forcing an update on the updatepanel, that update wont display until the page completes its postback.

I see that you are trying to place a time stamp in a textbox evertime the CallProcess routine completes.

You probably need to consider multiple textboxes and a Select Case statement:

For i = 1To 10

CallProcedureHere(i)

SelectCase i

Case 1
Textbox1.text = Now
Case 2
textbox2.text = Now

EndSelect

Next

No comments:

Post a Comment