CoverStory
LANGUAGES: VB.NET
ASP.NET VERSIONS: 2.0
Keeping It Simple
Enhance a Web-based RSS Reader Using the Microsoft
ASP.NET AJAX Framework
By Wei-Meng Lee
In Keep
It Simple I demonstrated how you can easily build an RSS Reader Web
application (see Figure 1) using the various features of ASP.NET 2.0. Shortly thereafter
Microsoft began releasing CTP releases of its new AJAX Framework, known by its
codename of Atlas .
Figure 1: The RSS Reader application
built in the previous article.
Toward the
completion of this article, Microsoft renamed ASP.NET Atlas as ASP.NET 2.0 AJAX. The client-side Atlas JavaScript library
is called the Microsoft AJAX Library; the server-side Atlas functionality
that integrates with ASP.NET is called ASP.NET 2.0 AJAX Extensions. Throughout this article you may
see traces of the word Atlas, but the functionality is otherwise unchanged.
Using the ASP.NET 2.0 AJAX Framework you can build more
responsive ASP.NET Web applications by reducing the amount of times your page
needs to be refreshed, and enrich the behavior of these applications by
including new client-side functionality. I thought the best way to really learn
a new framework is to actually build a project with it. And what better way to
do it than to enhance an existing application?
In this article I ll demonstrate how you can enhance the
original RSS Reader application using the ASP.NET 2.0 AJAX Framework. I suggest
you download the source for the original RSS Reader application; you should understand
how it works before following the instructions in this article. The original
application is available.
What You Need
To use Atlas you must first install one of the following
versions of Visual Web Developer:
You also need to download the latest version of the
ASP.NET 2.0 AJAX Framework, which you ll find at http://atlas.asp.net/default.aspx?tabid=47&subtabid=471.
Note: The version I used for this article is the July CTP release (you can
check the changes between the ASP.NET AJAX ( Atlas ) CTP and the Beta 2 and RTM
Releases from http://ajax.asp.net/files/AspNet_AJAX_CTP_to_Beta_Whitepaper.doc).
For additional AJAX functionality
you must download the ASP.NET AJAX Control Toolkit (previously known as the
Atlas Control Toolkit) from http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=AtlasControlToolkit.
See http://atlas.asp.net/atlastoolkit/Walkthrough/Setup.aspx
for instructions on how to install the ASP.NET AJAX Control Toolkit, as well as
Daniel N. Egan s article Working
with the ASP.NET AJAX Control Toolkit.
Atlas-enable Your Existing Application
The first step toward Atlas-enabling the RSS Reader
application is to add the necessary AJAX
libraries and modify the Web.config configuration. To do so, you must perform
the following steps:
- Open the RSS Reader Web project in Visual Studio
2005.
- Right-click the project name in Solution
Explorer and select Add ASP.NET Folder | Bin to add a Bin folder to your
project.
- Right-click the Bin folder and select Add
Existing Item. Select the Microsoft.Web.Atlas.dll library from the C:\Program
Files\Microsoft ASP.NET\Atlas\v2.0.50727\Atlas.
- Insert the code shown in bold in Figure 2 into
the <configuration> element of your application s Web.config file. (The
highlighted code can be copied directly from the Web.config file located in the
C:\Program Files\Microsoft ASP.NET\Atlas\v2.0.50727\Atlas folder.)
- Insert the code shown in bold in Figure 3 into
the <system.web> element in your application s Web.config file.
- Finally, insert the code shown in bold in Figure
4 into the <pages> element in your application s Web.config file.
<configuration xmlns="http://schemas.microsoft.com/
.NetConfiguration/v2.0">
<!--copied from Web.config file in
C:\Program Files\Microsoft ASP.NET\
Atlas\v2.0.50727\Atlas -->
<!--
The configSections define a section for
ASP.NET Atlas.
-->
<configSections>
<sectionGroup
name="microsoft.web"
type="Microsoft.Web.Configuration.MicrosoftWebSectionGroup">
<section name="converters"
type="Microsoft.Web.Configuration.ConvertersSection"
requirePermission="false" />
<section name="webServices"
type="Microsoft.Web.Configuration.WebServicesSection"
requirePermission="false" />
<section
name="authenticationService" type="Microsoft.
Web.Configuration.AuthenticationServiceSection"
requirePermission="false"
/>
<section
name="profileService"
type="Microsoft.Web.Configuration.ProfileServiceSection"
requirePermission="false" />
</sectionGroup>
</configSections>
<!--
The microsoft.web section defines items
required
for the Atlas framework.
-->
<microsoft.web>
<converters>
<add type="Microsoft.Web.Script.Serialization.
Converters.DataSetConverter"/>
<add
type="Microsoft.Web.Script.Serialization.
Converters.DataRowConverter"/>
<add
type="Microsoft.Web.Script.Serialization.
Converters.DataTableConverter"
/>
</converters>
<webServices
enableBrowserAccess="true" />
<!--
Uncomment this line to enable the authentication
service.
<authenticationService
enabled="true" />
-->
<!-- Uncomment these lines to enable the
profile service.
To allow profile properties to be
retrieved and modified
in Atlas applications, you need to add
each property name
to the setProperties and getProperties
attributes. If you
intend for all properties to be available,
you can use"*"
as a
shorthand rather than enumerating each property -->
<!--
<profileService
enabled="true"
setProperties="propertyname1;propertyname2"
getProperties="propertyname1;propertyname2" />
-->
</microsoft.web>
Figure 2: Place
this code into the <configuration> element of your application s
Web.config file.
<system.web>
<!--copied from Web.config file in
C:\Program Files\Microsoft
ASP.NET\Atlas\v2.0.50727\Atlas -->
<!-- ASMX is mapped to a new handler so
that proxy javascripts
can also be served.
-->
<httpHandlers>
<remove verb="*"
path="*.asmx"/>
<add verb="*" path="*.asmx"
type="Microsoft.Web.Services.ScriptHandlerFactory"
validate="false"/>
<!--
The MultiRequestHandler enables
multiple requests to be
handled in one roundtrip to the server.
Its use requires
Full Trust.
-->
<add verb="*"
path="atlasbatchcall.axd"
type="Microsoft.Web.Services.MultiRequestHandler"
validate="false"/>
<add verb="*"
path="atlasglob.axd"
type="Microsoft.Web.Globalization.GlobalizationHandler"
validate="false"/>
<!--
The IFrameHandler enables a limited
form of cross-domain
calls to 'Atlas' web services. This
should only be enabled
if you need this functionality and
you're willing to expose
the data publicly on the Internet. To
use it, you will also
need to add the attribute
[WebOperation(true,
ResponseFormatMode.Json, true)] on the
methods that you
want to be called cross-domain. This
attribute is by
default on any DataService's GetData
method.
<add verb="*"
path="iframecall.axd"
type="Microsoft.Web.Services.IFrameHandler"
validate="false"/>
-->
<add verb="*"
path="*.asbx"
type="Microsoft.Web.Services.ScriptHandlerFactory"
validate="false"/>
</httpHandlers>
<httpModules>
<add name="ScriptModule"
type="Microsoft.Web.Services.ScriptModule"/>
<add name="BridgeModule"
type="Microsoft.Web.Services.BridgeModule"/>
<add name="WebResourceCompression"
type="
Microsoft.Web.Services.WebResourceCompressionModule"/>
</httpModules>
Figure 3: Place
this code into the <system.web> element of your application s Web.config
file.
<system.web>
<pages>
<controls>
<add namespace="Microsoft.Web.UI"
assembly="Microsoft.Web.Atlas"
tagPrefix="atlas"/>
<add
namespace="Microsoft.Web.UI.Controls"
assembly="Microsoft.Web.Atlas"
tagPrefix="atlas"/>
</controls>
</pages>
Figure 4: Place
this code into the <pages> element in your application s Web.config file.
That s it! The RSS Reader project is now ASP.NET 2.0 AJAX-enabled.
Update Portions of a Page
The major restriction of the current RSS Reader
application is that the entire page will refresh whenever you select a feed
from the ListBox control. For example, if you are currently viewing the
postings from MSDN and then switch to Engadget.com, the entire page needs to be
reloaded to update the DataList control. Hence, the first thing we need to fix
is the DataList control. We would want its content to update without causing
the entire page to refresh. For this we ll use the Atlas UpdatePanel control. First,
in Default.aspx, switch to Source View and add the Atlas ScriptManager control:
<form id="form1" runat="server">
<atlas:ScriptManager
ID="ScriptManager1" runat="server"
EnablePartialRendering="True">
</atlas:ScriptManager>
The ScriptManager control is the brain that enables all
the various Atlas functions and should be positioned at the top of the page.
The EnablePartialRendering attribute allows part of the page to be refreshed.
Next, add an UpdatePanel control and position it just
above the DataList control. Then drag the DataList control into the UpdatePanel
control. Figure 5 shows the before-and-after screen shot of the page. Figure 6 shows
how the UpdatePanel control looks in code.
Figure 5: Embedding the DataList
control within an UpdatePanel control.
<atlas:UpdatePanel ID="UpdatePanel1"
runat="server">
<ContentTemplate>
<asp:DataList ID="DataList1"
runat="server" Width="760px"
ForeColor="Black" DataSourceID="XmlDataSource1"
CellPadding="2" BorderWidth="1px"
BorderColor="Tan"
BackColor="LightGoldenrodYellow">
<ItemTemplate>
<b>
<%#XPath("title")%>
</b>
<br />
<i>
<%#XPath("description")
%>
</i> <%#XPath("pubDate")%><br
/>
<a href='<%#XPath("link")
%>'>Link</a><br />
<br />
</ItemTemplate>
<FooterStyle
BackColor="Tan" />
<SelectedItemStyle
BackColor="DarkSlateBlue"
ForeColor="GhostWhite" />
<AlternatingItemStyle
BackColor="PaleGoldenrod" />
<HeaderStyle
BackColor="Tan" Font-Bold="True" />
</asp:DataList>
</ContentTemplate>
</atlas:UpdatePanel>
Figure 6: The
UpdatePanel control.
Notice that the DataList control is wrapped inside a
ContentTemplate element. However, simply wrapping the DataList control with the
UpdatePanel control is not enough to make the DataList update independently of
the page. You need to add a trigger to the UpdatePanel control. Atlas triggers
are used to specify the events that cause an UpdatePanel control to
automatically refresh. For our example, let s add a ControlValueTrigger trigger
(see Figure 7).
<atlas:UpdatePanel ID="UpdatePanel1"
runat="server">
<ContentTemplate>
<asp:DataList ID="DataList1"
runat="server" Width="760px"
...
...
</asp:DataList>
</ContentTemplate>
<Triggers>
<atlas:ControlValueTrigger
ControlID="lstSubscriptions"
PropertyName="SelectedValue" />
</Triggers>
</atlas:UpdatePanel>
Figure 7: This
type of trigger causes an update when the specified value of a control changes.
In this case, the DataList control will be updated
whenever the SelectedValue property of the lstSubscriptions ListBox control
changes. That is, whenever the user clicks on the list of feeds in the ListBox
control.
Press F5 to test the application. In the list of blogs,
click on any one of them and observe that the DataList control is now able to
update itself without refreshing the entire page.
Displaying a Progress Message
Although the DataList control can now update itself
without causing the entire page to refresh, you ll notice that the updates are
sometimes slow and there is no way to know if the DataList control is updating
or not. Hence, it would be useful to show a message to the user indicating that
the control is being updated. To do so, you can use the UpdateProgress control,
shown in bold in Figure 8.
<atlas:UpdatePanel ID="UpdatePanel1"
runat="server">
<ContentTemplate>
<atlas:UpdateProgress
ID="updateProgress1" runat="server">
<ProgressTemplate>
<asp:Label
ID="lblMessage" runat="server"
Text="Label"
Width="500">
Updating Blog Listings... Please
wait.
</asp:Label>
</ProgressTemplate>
</atlas:UpdateProgress>
...
...
Figure 8: The
UpdateProgress control.
Here I ve used a Label control to display the message Updating
Blog Listings... Please wait. You can also use an Image control to display an
animated GIF image.
Press F5 to test the application. Now when you click on a
feed you ll see the message and the message will disappear once the updating is
complete (see Figure 9).
Figure 9: Displaying the message
when the DataList control is being updated.
Sometimes the update is too fast and you won t have the
time to catch the message. To prevent this, insert a Sleep method in the
SelectedIndexChanged event of the lstSubscriptions control, as shown in Figure 10.
Protected Sub lstSubscriptions_SelectedIndexChanged( _
ByVal sender As Object, _
ByVal e As
System.EventArgs) _
Handles
lstSubscriptions.SelectedIndexChanged
Try
System.Threading.Thread.Sleep(2000)
'---Bind the
XmlDataSource control to the
' selected item
URL---
XmlDataSource1.DataFile
= _
lstSubscriptions.SelectedItem.Value
Catch ex As Exception
DisplayError("Error displaying the feed.")
End Try
End Sub
Figure 10: Insert
a Sleep method in the SelectedIndexChanged event of the lstSubscriptions
control.
Calling a Web Service from the Client
The next area we need to fix is the Verify Feed button
(see Figure 11).
Figure 11: The Verify Feed button
retrieves the feed title of a blog.
Before you subscribe to a feed, you must enter the feed
URL and then click the Verify Feed button to retrieve the title of the feed. As
usual, this will result in refreshing the entire page. A better way would be to
rewrite the logic for verifying the feed (and obtaining the feed title) as a
Web service so the client can directly connect to the Web service and obtain
(and update) the feed title on the page, all without causing a page refresh.
Adding the Web Service
The first step is to add a new Web service to the project.
In Solution Explorer, right-click on the project name and select Add New Item.
Select Web Service and use its default name of WebService.vb. The new
WebService.vb file should now be located in the App_Code folder of your project
(see Figure 12).
Figure 12: Adding a new Web service
to the project.
Double-click the WebService.vb file and import the
following namespaces:
Imports System.Net
Imports System.IO
Imports System.Xml
Next, declare the two helper functions shown in Figure 13.
Private Function SendRequest( _
ByVal URI As String, _
ByVal requestType As
String) As HttpWebRequest
Dim req As
HttpWebRequest = Nothing
Try
'---Creates a HTTP
request---
req =
HttpWebRequest.Create(URI)
req.Method =
requestType '---GET or POST---
Catch ex As Exception
Throw New
Exception("Error")
End Try
Return req
End Function
Private Function GetResponse( _
ByVal req As
HttpWebRequest) As String
Dim body As String =
String.Empty
Try
'---Get a response
from server---
Dim resp As
HttpWebResponse = req.GetResponse()
Dim stream As Stream
= resp.GetResponseStream()
'---Use a
StreamReader to read the response---
Dim reader As
StreamReader = _
New
StreamReader(stream, Encoding.UTF8)
body =
reader.ReadToEnd()
stream.Close()
Catch ex As Exception
Throw New
Exception("Error")
End Try
Return body
End Function
Figure 13: The SendRequest
and GetResponse functions.
The LoadFeed function will use the feed URL and retrieve
the title of the feed, as shown in Figure 14.
Public Function LoadFeed( _
ByVal URI As String) As
String
Dim req As
HttpWebRequest
Dim xmlDoc As
XmlDocument = Nothing
Try
req = SendRequest(URI,
"GET")
Dim xmlData As String
= GetResponse(req)
xmlDoc = New
XmlDocument()
xmlDoc.LoadXml(xmlData)
'---Select the title
of the document---
Dim titleNode As
XmlNode = _
xmlDoc.DocumentElement.SelectSingleNode( _
"channel/title")
Return
titleNode.InnerText
Catch ex As Exception
Return String.Empty
End Try
End Function
Figure 14: Retrieve
the title of the feed.
Finally, add the VerifyFeed Web method so that it can be
invoked directly by the client portion of the RSS application:
<WebMethod()> _
Public Function VerifyFeed(ByVal feedURL As String) As String
'---Load the RSS feed XML
document and extract the title---
Return LoadFeed(feedURL)
End Function
Adding the Client-side JavaScript
To be able to invoke the Web method from the client side,
you must write some client-side JavaScript. Add to the Source View of
Default.aspx the JavaScript shown in bold in Figure 15.
...
<head runat="server">
<title>Untitled
Page</title>
</head>
<script
type="text/javascript" language="javascript">
//---invoking the web method---
function btnVerifyFeed_Click()
{
req = WebService.VerifyFeed(
document.getElementById('txtRssURL').value,
onComplete, onTimeOut);
}
//---when the web method returns---
function onComplete(result)
{
if (result!="") {
document.getElementById('txtFeedTitle').value
= result;
document.getElementById('btnSubscribe').disabled = false;
}
else
{
alert("Feed did not load
correctly.");
}
}
//---when the web method times out---
function onTimeOut(result)
{
alert("Error accessing Web
service.");
}
</script>
<body>
...
Figure 15: Invoke
the Web method.
Replace the original Verify Feed Button control (see
Figure 16) with an HTML Input element:
<input id="btnVerifyFeed"
type="button"
value="Verify
Feed"
onclick="return
btnVerifyFeed_Click()" />
Figure 16: Replace the Button
control with an HTML Input element.
This is because you don t want a postback to occur when
the user clicks on the Verify Feed button; instead, it should invoke the
JavaScript code. Finally, add the Services element within the ScriptManager
element, as follows:
<atlas:ScriptManager ID="ScriptManager1"
runat="server"
EnablePartialRendering="True">
<Services>
<atlas:ServiceReference
Path="WebService.asmx" />
</Services>
</atlas:ScriptManager>
The Path attribute within the ServiceReference element
specifies the Web service to invoke. Press F5 to test the application. Enter a
feed URL and click the Verify Feed button. Notice that the page does not
refresh and the feed title will be displayed on the page.
Subscribing to a Feed
After a feed is verified you can subscribe to it by
clicking the Subscribe button. However, as usual, this will cause the ListBox
control (showing the list of subscribed feeds) to be updated and hence cause the
entire page to refresh. This is our next target for modification.
First, add an UpdatePanel control on top of the ListBox
control (see Figure 17). Then drag the ListBox control onto the UpdatePanel
control. Figure 17 shows the before-and-after effects.
Figure 17: Embedding the ListBox
control within an UpdatePanel control.
Switch to the Source View of the page and add a trigger to
the UpdatePanel control:
<atlas:UpdatePanel ID="UpdatePanel2"
runat="server">
<ContentTemplate>
<asp:ListBox
ID="lstSubscriptions" runat="server"
AutoPostBack="True" Width="136px"
Height="236px"></asp:ListBox>
</ContentTemplate>
<Triggers>
<atlas:ControlEventTrigger
ControlID="btnSubscribe"
EventName="Click" />
</Triggers>
</atlas:UpdatePanel>
This time you re adding a ControlEventTrigger trigger.
This type of trigger causes an update to the UpdatePanel control when the
specified control (btnSubscribe, in this case) raises a specified event (Click,
in this case).
Press F5 to test the application. You can now verify a
feed URL by clicking the Verify Feed button. To subscribe to the feed, simply
click the Subscribe button and the newly subscribed feed will appear in the
ListBox control. All this happens without causing a single page refresh!
Floating Panel
You can now subscribe to feeds without refreshing the
page. In addition, switching from one feed to another does not cause any page
refresh. Let s see what else we can improve.
If you use the application for some time you ll realize
that you must constantly scroll to the top of the page before you can select
another feed (see Figure 18). This is because the ListBox control is positioned
at the top of the page. A better way would be to make the ListBox control a
floating panel that will always appear at a particular position on the page.
Figure 18: You must scroll to the
top of the page before you can select another feed.
First, add a Panel control below the Unsubscribe button
(see Figure 19). Set the BorderStyle property of the Panel control to Solid.
Then move the wordings Subscribed Feeds, the UpdatePanel control, and the
Unsubscribe control into the Panel control. Figure 19 shows the
before-and-after effects.
Figure 19: Moving the various
controls into a Panel control.
Also, expand the width of the ListBox control so that it
is wider (see Figure 20). Next, add to the page the
AlwaysVisibleControlExtender control (found in the ASP.NET AJAX Control Toolkit).
Configure the AlwaysVisibleControlExtender control as shown in Figure 21.
Figure 20: Widening the Panel
control and adding the AlwaysVisibleControlExtender control.
<asp:Panel ID="Panel1" runat="server"
BorderStyle="Solid"
Height="50px"
Width="300px">
...
...
</asp:Panel>
<cc1:AlwaysVisibleControlExtender
ID="AlwaysVisibleControlExtender1"
runat="server">
<cc1:AlwaysVisibleControlProperties
TargetControlID="Panel1"
VerticalSide="Top"
HorizontalSide="Right"
HorizontalOffset="10"
VerticalOffset="10"
ScrollEffectDuration="0.1" />
</cc1:AlwaysVisibleControlExtender>
Figure 21: Configure
the AlwaysVisibleControlExtender control.
The AlwaysVisibleControlExtender control allows a Panel
control to always remain visible. You configure it using the
AlwaysVisibleControlProperties element. Its attributes are:
- TargetControlID; the control that will always be
visible.
- VerticalSide; the vertical alignment of the
control (Top or Bottom).
- HorizontalSide; the horizontal alignment of the
control (Left or Right).
- HorizontalOffset; the number of pixels away from
the horizontal edge of the window the control must be.
- VerticalOffset; the number of pixels away from
the vertical edge of the window the control must be.
- ScrollEffectDuration; the length in seconds of
the scrolling effect to last when the target control is repositioned.
Press F5 to test the application. You ll now see that the
Panel control containing the ListBox and Button controls is always visible (see
Figure 22).
Figure 22: The Panel containing the
ListBox and Button controls is always visible.
Using Drag and Drop to Reposition Controls
The last modification we want to make to the RSS Reader
application is to allow users to reposition the location of controls by
drag-and-drop. A good candidate for this operation is the part of the page that
allows users to verify and subscribe to a feed. Using a Panel control, enclose
the two TextBox and Button controls (see Figure 23).
Figure 23: Enclosing the TextBox and
Buttons controls within a Panel control.
Set the properties of the Panel control as follows:
- Backcolor: #C0C0FF
- BorderStyle: Double
The Source View of the Panel control looks like that shown
in Figure 24.
<asp:Panel ID="Panel2" runat="server"
BorderStyle="Double"
Height="50px"
Width="532px" BackColor="#C0C0FF"><br />
Feed URL:
<asp:TextBox
ID="txtRssURL" runat="server"
Width="336px"></asp:TextBox>
<input
id="btnVerifyFeed" type="button" value="Verify
Feed"
onclick="return
btnVerifyFeed_Click()" /><br />
Feed Title:
<asp:TextBox
ID="txtFeedTitle" runat="server"
Font-Bold="True"
ForeColor="Red" Width="340px">
</asp:TextBox>
<asp:Button
ID="btnSubscribe" runat="server" Text="Subscribe"
Width="99px"
OnClientClick="return
document.getElementById('btnSubscribe').disabled = false;" />
<br />
</asp:Panel>
Figure 24: Source View
of the Panel control.
To make the Panel control drag-able, use the
DragOverlayExtender control and configure it as follows:
<atlas:ScriptManager ID="ScriptManager1"
runat="server"
EnablePartialRendering="True">
<Services>
<atlas:ServiceReference
Path="WebService.asmx" />
</Services>
</atlas:ScriptManager>
<atlas:DragOverlayExtender ID="DragOverlayExtender1"
runat="server">
<atlas:DragOverlayProperties
Enabled="true"
TargetControlID="Panel2" />
</atlas:DragOverlayExtender>
Press F5 to test the application; you ll be able to drag
and drop the Panel control anywhere on the page (see Figure 25).
Figure 25: Dragging the Panel
control to any location on the page.
Remember the Last Drop Position
Although you can drag and drop the Panel control anywhere
on the page, it won t be able to remember the last position when you restart
the application. To do so, you must save the last drop position using the
Profile service. In Web.config, add a new Profile property, as shown in bold here:
<profile>
<properties>
<add
name="FeedNames" type="System.String"/>
<add
name="FeedURLs" type="System.String"/>
<add name="PanelLocation"
type="System.String" />
</properties>
</profile>
Uncomment the <profileService> element in the Web.config
file and set the setProperties and getProperties attributes as shown in bold here:
<profileService enabled="true"
setProperties="PanelLocation"
getProperties="PanelLocation" />
This will cause the Profile property PanelLocation to be
exposed to the client-side code. Back in the Source View of Default.aspx, add
the <atlas:ProfileScriptService> element to the page and set its AutoSave
attribute to true:
<atlas:DragOverlayExtender ID="DragOverlayExtender1"
runat="server">
<atlas:DragOverlayProperties
Enabled="true"
TargetControlID="Panel2" />
</atlas:DragOverlayExtender>
<atlas:ProfileScriptService
ID="ProfileScriptService1"
runat="server"
AutoSave="true" />
Add the ProfileProperty attribute to the
DragOverlayProperties control and set it to PanelLocation:
<atlas:DragOverlayExtender ID="DragOverlayExtender1"
runat="server">
<atlas:DragOverlayProperties
Enabled="true"
TargetControlID="Panel2"
ProfileProperty="PanelLocation"/>
</atlas:DragOverlayExtender>
<atlas:ProfileScriptService
ID="ProfileScriptService1"
runat="server"
AutoSave="true" />
That s it! Press F5 to test the application. You can now
drag and drop the Panel control and then restart the application. The last drop
position of the Panel control will be persisted and restored when you log in to
the application.
Conclusion
You ve seen how easy it is to use the ASP.NET 2.0 AJAX
Extensions to enhance the responsiveness of your current ASP.NET 2.0
applications. If you want to learn more about the Microsoft ASP.NET 2.0 AJAX Framework,
check out my latest Short Cuts from O Reilly: Getting Started with Atlas (http://www.oreilly.com/catalog/atlaspdf/).
The source code accompanying
this article is available for download.
Wei-Meng Lee (http://weimenglee.blogspot.com) is a
Microsoft MVP and founder of Developer Learning Solutions (http://www.learn2develop.net), a
technology company specializing in hands-on training on the latest Microsoft
technologies. He is an established developer and trainer specializing in .NET
and wireless technologies. Wei-Meng speaks regularly at international
conferences and has authored and co-authored numerous books on .NET, XML, and
wireless technologies. He writes extensively on topics ranging from .NET to Mac
OS X. He is also the author of.NET Compact
Framework Pocket Guide, ASP.NET 2.0: A
Developer s Notebook (both from O Reilly Media, Inc), and Programming Sudoku (Apress).