In my last entry (AJAX News Rotator Part I), I described how I used the NewsManager in Sitefinity to create an AJAX news rotator that dynamically fetches news content using AJAX. Using the linkbuttons in the repeater, users can jump to different items in the list. However, this isn't exactly a "rotator", because to me that implies some sort of automation, which sounds like a good job for the ASP.NET Timer control.
Since most of the logic to retrieve and update the news panel is already built, I only needed a way to automate the transition from item to item. So I started by including a Timer control, making sure to place it inside of the RadAjaxPanel.
<telerik:RadAjaxPanel ID="NewsAjaxPanel" runat="server" Width="550" Height="185" LoadingPanelID="NewsLoadingPanel">
<div id="newsFrame" class="newsFrame">
...
</div>
<div class="newsNav">
...
</div>
<asp:timer id="Timer1" runat="server" interval="10000" ontick="Timer1_Tick" />
</telerik:RadAjaxPanel>
Setting the timer to 10 seconds, I now need to handle the "tick" event, reusing the code from our last article to update the new item after advancing the current item to the next entry.
protected void Timer1_Tick(object sender, EventArgs e)
{
// unselect css before changing
LinkButton selectedLink = newsNavRepeater.Controls[CurrentItem].FindControl("lnkItem") as LinkButton;
selectedLink.CssClass = "";
CurrentItem++;
IContent newsItem = manager.Content.GetContent(newsIDs[CurrentItem]);
UpdateNews(newsItem);
}
As you can see, we first use the current index to disable the "selected" css class on the current item before advancing the indexer to the next entry and loading the next news item. Pretty simple huh!
One minor issue I encountered was the increment operator. Normally, I would have incremented the indexer inline, saving a line of code by instead using newsIDs[++CurentItem]. Unfortunately, for some reason or another, this method bypassed my get/set logic, incrementing the indexer CurrentItem WITHOUT running the set check for validity. I'm not sure if this is a bug, or a misunderstanding on my part regarding the order of operations or what. I'll report back if I learn anything new, but for now, separating the increment into its own code seems to do the trick.
Now, in addition to having the news rotate automatically through all the items, it's a good idea to have a way for users to "pause" an item so that they can have time to read it before the item disappears. This is just a matter of adding another link button to the page, and toggling the Enabled property of the Timer based on the CommandArugment of the button (which is also toggled, opposite the value of the Timer). First we add the Toggle Button
<div class="newsNav">
<asp:linkbutton id="lnkToggle" runat="server" commandargument="pause" text="Pause" oncommand="lnkToggle_Command" cssclass="toggle" />
<asp:repeater id="newsNavRepeater" runat="server" onitemdatabound="newsNavRepeater_ItemDataBound" onitemcommand="newsNavRepeater_ItemCommand">
<ItemTemplate>
<asp:LinkButton ID="lnkItem" runat="server" />
</ItemTemplate>
</asp:repeater>
</div>
Next I need to handle the click, toggling the status of the Timer. Notice that on resume, I go ahead and tick the timer so that the rotator acutally "resumes" ticking.
protected void lnkToggle_Command(object sender, CommandEventArgs e)
{
switch (e.CommandArgument.ToString())
{
case "pause":
lnkToggle.Text = "Resume";
lnkToggle.CommandArgument = "resume";
Timer1.Enabled = false;
break;
case "resume":
lnkToggle.Text = "Pause";
lnkToggle.CommandArgument = "pause";
// unselect css before changing
LinkButton selectedLink = newsNavRepeater.Controls[CurrentItem].FindControl("lnkItem") as LinkButton;
selectedLink.CssClass = "";
Timer1.Enabled = true;
Timer1_Tick(this, null);
break;
}
}
There is just one more issue to resolve here. Since I am using Sitefinity, in the Admin mode while previewing it, I kept getting AJAX errors since the page is hosted in a different context, wrapped around by the Admin panel. As a result, to avoid errors, it was necessary for me to disable the rotator when in Page Edit mode. Checking the Sitefinity Forums, the only way I can detect this is by inspecting the QueryString for the presence of the cmspagemode key.
protected void Page_Load(object sender, EventArgs e)
{
Timer1.Enabled = !IsPageInAdmin();
// ...
}
private bool IsPageInAdmin()
{
// will return TRUE is the page is viewed in administration part
if (this.Page.Request.RawUrl.IndexOf("cmspagemode=preview") > 0)
return true;
// will return TRUE is the page is in editing mode
if (this.Page.Request.RawUrl.IndexOf("cmspagemode=edit") > 0)
return true;
// the page is viewed in the public part.
return false;
}
And that's all there is to it! Next entry, I'm going to tackle the last piece of the puzzle: handling browsers that have Javascript disabled.
Enjoyed this post and/or found it useful?