Saturday, 10 December 2016

AJAX.NET 7 : Timer control

Timer control

Timer controls allow you to do postbacks at certain intervals. If used together with UpdatePanels, which is the most common approach, it allows for timed partial updates of your page, but it can be used for posting back the entire page as well. In this chapter we will focus on using timers with UpdatePanels, so if you haven't already read the chapter on UpdatePanels, please do so now. 

Here is a small example of using the Timer control. It simply updates a timestamp every 5 seconds.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Timers</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
        <asp:Timer runat="server" id="UpdateTimer" interval="5000" ontick="UpdateTimer_Tick" />
        <asp:UpdatePanel runat="server" id="TimedPanel" updatemode="Conditional">
            <Triggers>
                <asp:AsyncPostBackTrigger controlid="UpdateTimer" eventname="Tick" />
            </Triggers>
            <ContentTemplate>
                <asp:Label runat="server" id="DateStampLabel" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
</body>
</html>
We only have a single CodeBehind function, which you should add to your CodeBehind file:
protected void UpdateTimer_Tick(object sender, EventArgs e)
{
    DateStampLabel.Text = DateTime.Now.ToString();
}
This is all very simple. We have a normal UpdatePanel, which carries a Trigger reference to our new Timer control. This means that the panel is updated when the Timer "ticks", that is, fires the Tick event. The Timer control uses the interval attribute to define the number of milliseconds to occur before firing the Tick event. As you can see from our CodeBehind code listing, we just update the DateStampLabel each time the Timer fires. This could be done more efficient with a simple piece of JavaScript, which updates the time on the clientside instead of involving the server. The example is only used to demonstrate the potential of the Timer control. 

Another approach is including the Timer inside the UpdatePanel. Doing so would save us from defining a trigger, but you should be aware of the fact that the behavior will be different, depending on whether you have the Timer inside or outside an UpdatePanel. When a Timer is inside an UpdatePanel, the Timer is not re-constructed until the UpdatePanel is fully updated. That means that if you have a Timer with an interval of 60 seconds, and the update takes 5 seconds, the next event won't be fired 60 seconds after the previous, but 65 seconds after. On the other hand, if the Timer is outside the UpdatePanel, the user will only look at the content of the panel for 55 seconds before it's updated again. 

You should always remember that even though partial updates are not as heavy on the server as real postbacks, the server is still contacted, and when using timers, you may get a lot of partial postbacks, which can slow things down. Always use as high intervals as possible, and consider if contacting the server is really necessary or not.

AJAX.NET 6: UpdateProgress control

Update Progress control

One of the problems with Ajax, is the fact that since it's asynchronus and in the background, the browser will not show you any status. With fast servers and fast methods, this is not a big problem, but whenever you have a method which takes up a bit of time, the user is very likely to get impatient. 

Fortunately, ASP.NET AJAX solves this problem for us as well, with a nice control called UpdateProgress. It will use your own template to show that an asynchronus method is working. Have a look at the following example, which will show the control in action. It will be explained afterwards.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>UpdateProgress control</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
        <asp:UpdateProgress runat="server" id="PageUpdateProgress">
            <ProgressTemplate>
                Loading...
            </ProgressTemplate>
        </asp:UpdateProgress>
        <asp:UpdatePanel runat="server" id="Panel">
            <ContentTemplate>
                <asp:Button runat="server" id="UpdateButton" onclick="UpdateButton_Click" text="Update" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
</body>
</html>
The following method should be added to your CodeBehind file:
protected void UpdateButton_Click(object sender, EventArgs e)
{
    System.Threading.Thread.Sleep(5000);
}
This simple example will just show you how easy it is to use the UpdateProgress control. Once the button is clicked, the script sleeps for 5 seconds (don't use code like that in your real projects - it's for demonstrational purposes only!), and the "Loading..." text is displayed on your page. You can use anything in the ProgressTemplate, including ordinary markup and other controls. A common use is an animated GIF, positioned strategically on the page using CSS positioning. 

You can even have multiple UpdateProgress controls on the page, and by using the AssociatedUpdatePanelID property, you can make sure that the UpdateProgress is only shown when a certain UpdatePanel is updated. 

The DynamicLayout property is nice to know as well. It tells whether or not the page should reserve space for your progress control. If it's set to true, which is the default, the space is dynamic, hence it's not reserved, but taken when the control is shown. If you wish to reserve the space, set this property to false. To see the difference, add the property to our example and change it back and forth. 

If some of your postbacks are fast, the UpdateProgress will only be shown for a very short amount of time, resulting in a blinking behavior, which may confuse your users. For that reason, you may specify a minimum amount of time to occur before showing the progress control. This can be done with the DisplayAfter attribute. Specify a number of milliseconds to elapse before showing the progress control, e.g. 2000 if you wish to wait for 2 seconds.

AJAX.NET 5 :UpdatePanel history

Update Panel history

A big problem with AJAX enabled pages in general, is that, by design, each action doesn't represent a state in your browser, which means that you can't use the Back and Forward buttons to shift between states, and because the URL doesn't change, a specific state can't be bookmarked or linked to by the user. This effectively limits the situations in where you can use AJAX in general and the UpdatePanel control specifically. Fortunately, Microsoft has solved this problem with the History feature. It can be enabled on the ScriptManager control, and basically works by adding information to the URL after the # character, which is normally mostly used for navigating between various parts of the same page. Let's try creating a sample page which will show you the problem, and then we fix it afterwards:
<asp:ScriptManager runat="server" ID="MainScriptManager" />

<asp:UpdatePanel runat="server" ID="pnlColorSelect">
<ContentTemplate>
    <asp:DropDownList runat="server" ID="ddlColor" AutoPostBack="true" OnSelectedIndexChanged="ddlColor_SelectedIndexChanged">
        <asp:ListItem Value="Red">Red</asp:ListItem>
        <asp:ListItem Value="Blue">Blue</asp:ListItem>
        <asp:ListItem Value="Green">Green</asp:ListItem>
    </asp:DropDownList>
    <br /><br />
    Selected color: <asp:Label runat="server" ID="lblSelectedColor" />
</ContentTemplate>
</asp:UpdatePanel>    
We also need a CodeBehind method to handle the selection of a new color:
protected void ddlColor_SelectedIndexChanged(object sender, EventArgs e)
{
    lblSelectedColor.Text = ddlColor.SelectedValue;
    lblSelectedColor.BackColor = System.Drawing.Color.FromName(ddlColor.SelectedValue);
}
It's really quite simple, so try running the page and see for your self. When you select a new color from the dropdown list, the change is reflected in the label control below it, and because of the UpdatePanel around it, no real postback is performed and the label is updated without the page reloading. This is all very good, but as you can see, no matter how many times you change the color, the URL does not change and no state is tracked, resulting in dead Back and Forward buttons. Let's change that, by making the following changes: The ScriptManager should have the EnableHistory property set to True and we need to subscribe to the OnNavigate event, like this:
<asp:ScriptManager runat="server" ID="MainScriptManager" EnableHistory="true" OnNavigate="MainScriptManager_Navigate" />
In the CodeBehind, we add a single line to our dropdown list event, and then we define our Navigate event for the ScriptManager, like this:
protected void ddlColor_SelectedIndexChanged(object sender, EventArgs e)
{
    lblSelectedColor.Text = ddlColor.SelectedValue;
    lblSelectedColor.BackColor = System.Drawing.Color.FromName(ddlColor.SelectedValue);
    MainScriptManager.AddHistoryPoint("SelectedColor", ddlColor.SelectedValue);
}

protected void MainScriptManager_Navigate(object sender, HistoryEventArgs e)
{
    string color = e.State["SelectedColor"];
    if (!String.IsNullOrEmpty(color))
    {
        lblSelectedColor.Text = color;
        lblSelectedColor.BackColor = System.Drawing.Color.FromName(color);
    }
}
Try running the page now. Each time you change the color, you will see the URL change, but still without a real postback/page reload, and you can now use your Back/Forward buttons in the brower. You will also see that the URL in the address bar actually be copied to a new browser window, and when the page is loaded, the color is now the same as when you copied the URL. It works! One thing that might bother you, is the fact that the URL looks very cryptic, like this: 

Default.aspx#&&/wEXAQUNU2VsZWN0ZWRDb2xvcgUFR3JlZW6BwCysI0shYsZauxImdaPIIPEYSA== 

That's because the values are encoded for security reasons. However, in a lot of cases, the values you store are really not that important and you might want a more naturally looking URL instead of the more secure one. This can be accomplished by using the EnableSecureHistoryState property on the ScriptManager, like this:
<asp:ScriptManager runat="server" ID="MainScriptManager" EnableHistory="true" OnNavigate="MainScriptManager_Navigate" EnableSecureHistoryState="false" />
Now when you use the page, the URL will look like this instead: 

Default.aspx#&&SelectedColor=Red 

Much simpler, but obviously it also allows the user to enter values that you may not have expected, which you should consider and prepare for when using this feature.

AJAX.NET 4: UpdatePanel control

UpdatePanel control

The UpdatePanel control is probably the most important control in the ASP.NET AJAX package. It will AJAX'ify controls contained within it, allowing partial rendering of the area. We already used it in the Hello world example, and in this chapter, we will go in depth with more aspects of the control. 

The <asp:UpdatePanel> tag has two childtags - the ContentTemplate and the Triggers tags. The ContentTemplate tag is required, since it holds the content of the panel. The content can be anything that you would normally put on your page, from literal text to web controls. The Triggers tag allows you to define certain triggers which will make the panel update it's content. The following example will show the use of both childtags.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>UpdatePanel</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
        <asp:UpdatePanel runat="server" id="UpdatePanel" updatemode="Conditional">
        <Triggers>
            <asp:AsyncPostBackTrigger controlid="UpdateButton2" eventname="Click" />
        </Triggers>
            <ContentTemplate>
                <asp:Label runat="server" id="DateTimeLabel1" />
                <asp:Button runat="server" id="UpdateButton1" onclick="UpdateButton_Click" text="Update" />               
            </ContentTemplate>
        </asp:UpdatePanel>
        <asp:UpdatePanel runat="server" id="UpdatePanel1" updatemode="Conditional">           
            <ContentTemplate>
                <asp:Label runat="server" id="DateTimeLabel2" />
                <asp:Button runat="server" id="UpdateButton2" onclick="UpdateButton_Click" text="Update" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
</body>
</html>
Here is the CodeBehind. Just add the following method to the file:
protected void UpdateButton_Click(object sender, EventArgs e)
{
    DateTimeLabel1.Text = DateTime.Now.ToString();
    DateTimeLabel2.Text = DateTime.Now.ToString();
}
So, what's this example all about? Try running it, and click the two buttons. You will notice that then first button updates only the first datestamp, while the second button updates both. Why? We have set the Panels to update conditionally, which means that their content is only updated if something insides them causes a postback, or if one of the defined triggers are fired. 

As you can see, the first UpdatePanel carries a trigger which references the second button. This will ensure that the first panel is updated even when a control on a different UpdatePanel is used. 

The AsyncPostBackTrigger tag is pretty simple - it only takes two attributes, the controlid, a reference to the control which can trigger it, and the eventname, which tells which eventtype can cause the trigger to fire. If you wish for the content of a UpdatePanel to be updated no matter what, you may change the updatemode property to Always. 

In general, you should only have UpdatePanels areound areas where you wish to do partial updates. Don't wrap your entire page within an UpdatePanel, and don't be afraid to use several panels, since this will give you more control of which areas update and when they do it.

AJAX.NET 3 :Hello, world!

Hello, world!

As usual, we will use the good old "Hello, world!" as our very first example. We will begin with the code, and then we'll do a bit of explanation afterwards. If you haven't already done so, you should create a new ASP.NET website project in Visual Studio Express 2012. The IDE will create a Default.aspx and Default.aspx.cs file for you, which will look just like any other ASP.NET enabled page. Let's add some AJAX to it:
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Hello, world!</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="MainScriptManager" runat="server" />
        <asp:UpdatePanel ID="pnlHelloWorld" runat="server">
            <ContentTemplate>
                <asp:Label runat="server" ID="lblHelloWorld" Text="Click the button!" />
                <br /><br />
                <asp:Button runat="server" ID="btnHelloWorld" OnClick="btnHelloWorld_Click" Text="Update label!" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
</body>
</html>
In the CodeBehind, there's nothing new except for this event which you should add:
protected void btnHelloWorld_Click(object sender, EventArgs e)
{
    lblHelloWorld.Text = "Hello, world - this is a fresh message from ASP.NET AJAX! The time right now is: " + DateTime.Now.ToLongTimeString();
}
In the markup part, we use two new things, when compared to regular ASP.NET: The ScriptManager control and the UpdatePanel control. The ScriptManager makes sure that the required ASP.NET AJAX files are included and that AJAX support is added, and has to be included on every page where you wish to use AJAX functionality. 

After the manager, we have one of the most used controls when working with AJAX, the UpdatePanel. This control allows you to wrap markup which you would like to allow to be partially updated, that is, updated without causing a real postback to the server. More about the UpdatePanel in a coming chapter. Besides those two controls, everything else is standard controls, with no modifications that would indicate alternate behavior. 

Try running the example site, and click the button. The label will be updated with our usual Hello world text, and the current time. Try repeatedly clicking the button, and you will see the label get the current timestamp each time. Notice the wonderful absence of a blinking window and a running status bar - everything is done without updating anything but the label! We've just created our first AJAX enabled page. If you wish to see how this page would work without AJAX, try setting the "enablepartialrendering" of the ScriptManager to false like this:
<asp:ScriptManager ID="MainScriptManager" runat="server" enablepartialrendering="false" />
This will disallow the use of partial rendering on the page, and show you how it would work without AJAX. 

In the following chapters we will look into the various AJAX controls and how to use them.