Upload
prokopis-pr
View
111
Download
3
Tags:
Embed Size (px)
DESCRIPTION
test description
Citation preview
DotNetNuke TabStrip WebControl Rendering A Detailed Discussion On the Four Modes of Rendering the DNNTabStrip
Jon Henning
Revision 1.0.0
Last Updated: August 11, 2006
Applies to: DotNetNuke v. 3.5/4.5
1
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Information in this document, including URL and other Internet Web site references, is
subject to change without notice. The entire risk of the use or the results of the use of
this document remains with the user.
The example companies, organizations, products, domain names, e-mail addresses,
logos, people, places, and events depicted herein are fictitious. No association with any
real company, organization, product, domain name, email address, logo, person,
places, or events is intended or should be inferred.
Complying with all applicable copyright laws is the responsibility of the user. Without
limiting the rights under copyright, no part of this document may be reproduced,
stored in or introduced into a retrieval system, or transmitted in any form or by any
means (electronic, mechanical, photocopying, recording, or otherwise), or for any
purpose, without the express written permission of Perpetual Motion Interactive
Systems, Inc. Perpetual Motion may have patents, patent applications, trademarks,
copyrights, or other intellectual property rights covering subject matter in this
document. Except as expressly provided in any written license agreement from
Perpetual Motion, the furnishing of this document does not give you any license to these
patents, trademarks, copyrights, or other intellectual property.
© 2005 Perpetual Motion Interactive Systems, Inc. All rights reserved.
DotNetNuke® and the DotNetNuke logo are either registered trademarks or
trademarks of Perpetual Motion Interactive Systems, Inc. in the United States and/or
other countries.
The names of actual companies and products mentioned herein may be the trademarks
of their respective owners.
2
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Abstract
The purpose of this guide to is to inform the developer utilizing the DNNTabStrip control
about the trade-offs to consider when choosing a rendering method.
3
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Contents
Chapter 1: Getting Started ................................................... 5
Introduction .................................................................................................................... 5
Chapter 2: Stages ................................................................ 7
Overview ...........................................................................................................................7
Stage 1 – Initial Load - Server Processing ....................................................................... 8
Stage 2 – Initial Load - Payload .....................................................................................10
Stage 3 – Tab Click - Request ......................................................................................... 11
Stage 4 – Tab Click – Server Processing ........................................................................ 13
Stage 5 – Tab Click - Payload ......................................................................................... 14
Chapter 4: Sample Code ..................................................... 17
Markup ........................................................................................................................... 17
CodeFile - Properties ...................................................................................................... 18
CodeFile – Event Handlers and Methods ...................................................................... 19
TabRenderMode - Final Thoughts ................................................................................ 22
Chapter 5: TabCallbackPostMode ..................................... 24
Introduction .................................................................................................................. 24
DNNTabStrip Wizard Sample ....................................................................................... 24
TabCallbackPostMode: Form ....................................................................................... 24
TabCallbackPostMode: TabStrip ................................................................................. 25
4
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
TabCallbackPostMode: DNNVariable .......................................................................... 29
TabCallbackPostMode: None ....................................................................................... 30
TabCallbackPostMode Conclusion................................................................................. 31
Chapter 6: CallBackType ................................................... 32
Chapter 7: Conclusion ...................Error! Bookmark not defined.
Additional Information ..................................................... 36
Appendix A: Document History ........................................ 37
5
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Chapter 1: Getting Started
Introduction
In the past I had blogged about the UpdatePanel control found inside Microsoft’s Atlas.
At that time I expressed reservations regarding how it “automagically” transforms your
page into an AJAX enabled one. I stated, "I do NOT think that partial rendering is the
best solution. Using it still requires the entire page to post back to the server and also
causes the webserver to process the entire page. It is only in the response from the
server that payload is minimized. In addition to the decrease in payload, the user does
not see the flicker of the page, since only part of the page is updated. A better solution
would be to change the modules to do their own highly specific AJAX calls to retrieve
only the necessary data." Seeing that very few developers were adopting the “highly
specific AJAX calls” into their modules, I figured I would try and offer a control that
offers a similar ease of implementation without nearly as many negative side effects.
This led me to develop the DNNTabStrip WebControl. I readily admit that this control
may not “just work” when plugged into an existing module in the same manner that the
UpdatePanel tries to accomplish. There are a few hurdles that I ran into when coding
against the new control, some of which I note here. Before I go into more detail, I feel
that I need to state a difference in mentality between the UpdatePanel and the
DNNTabStrip.
The DNNTabStrip AJAX capabilities were added to allow a page’s contents to be broken
up where only the displayed information is rendered on the server and passed to the
client. As the client requests a new tab, only that tab’s server-side processing takes place
and only that tab’s content is rendered to the client. While the UpdatePanel also handles
this use-case, it assumes you want to do much more. It is possible to use the
UpdatePanel and have the details from the first tab affect the rendering of the tab that is
requested. This default capability is the main reason why the UpdatePanel is not nearly
as efficient as the callback rendering mode of the DNNTabStrip.
This difference also accounts for the need to write your code-behind a little different than
you usually do when using the Callback rendering mode. Typically a developer will look
at the Page’s IsPostBack method to determine if data should be defaulted in the controls
6
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
or if the controls data will come from the page’s postback. For controls that are
contained within a tab, you will need to use the Tab’s IsPostBack property to determine
the action to take. The sample that this document covers demonstrates this technique.
This document discusses a single web-page that has the ability to demonstrate all four
modes of rendering: Load All Tabs On Client Sample, Load Tabs Through Postback,
Load Tabs Through Callback, and Load Tabs Through Partial Rendering. In addition to
demonstrating how each mode works, it also provides detailed information on the cost of
each phase.
7
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Chapter 2: Stages
Overview
1) Initial Request - Server ProcessingThis stage measures the amount of worknecessary on the server side in order toprocess the initial request.
2) Initial Request - PayloadThis stage measures the size of thepayload sent down to the client on theinitial request.
3) Tab Clicked - RequestThis stage measures the payload sizefrom the client request to the server.
4) Tab Clicked - Server ProcessingThis stage measures the amount ofserver-side processing necessary tofacilitate the request for the new tab.
5) Tab Clicked - PayloadThis stage measures the size of thepayload sent down to the client thatrequested a new tab.
DotNetNuke TabStrip Control
Stages Included in Evaluation
8
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
I suggest reviewing the diagram above while reading through this material. You may
also check out the live sample at this url:
http://webcontrols.dotnetnuke.com/samples.net2/TabStripRendering.aspx?id=100&mode=0. If
you are a developer, you may also wish to download the complete source from the
DotNetNuke WebControl’s Project Download Page. What follows, is the analysis derived
from this sample.
Stage 1 – Initial Load - Server Processing
This stage measures the amount of work necessary on the server side in order to process
the initial request.
All Client - Worst
The initial processing for the TabRenderingMode of All is pretty bad as one would
expect. We are processing all tabs on the initial request. You will see that this is a
benefit if the user ends up clicking on each tab, but in cases where the user chooses not
to open other tabs, this mode is far from optimal.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8783
9
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. SetupDefaults: tabAdvanced (Delay 1secs)
7. RefreshColors
8. BindTab: tabAdvanced (Delay 1secs)
9. tabAdvanced clicked
Postback - Best
The initial server processing here includes only what is displayed, therefore it is the best
approach.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8047
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
7. >>> POSTBACK - Size: 1440
8. >>> Render Size: 9906
9. SetupDefaults: tabGeneral
10. SetupDefaults: tabAdvanced (Delay 1secs)
11. RefreshColors
12. BindTab: tabAdvanced (Delay 1secs)
Callback – Best
The initial server processing here includes only what is displayed, therefore it is the best
approach.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 7618
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
7. >>> CALLBACK - Size: 65
8. SetupDefaults: tabAdvanced (Delay 1secs)
9. RefreshColors
10. BindTab: tabAdvanced (Delay 1secs)
11. >>> Render Size: 1281
Partial Rendering – Best
The initial server processing here includes only what is displayed, therefore it is the best
approach.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8633
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
** 7. >>> POSTBACK - Size: 4949
10
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
** 8. SetupDefaults: tabGeneral (Delay 1secs)
** 9. SetupDefaults: tabAdvanced (Delay 1secs)
** 10. RefreshColors
** 11. BindTab: tabAdvanced (Delay 1secs)
** 12. >>> Render Size: 5616
Stage 2 – Initial Load - Payload
This stage measures the size of the payload sent down to the client on the initial request.
All Client - Worst
The initial load for the TabRenderingMode of All is pretty bad as one would expect. We
are loading the html from all tabs on the initial request. You will see that this is a benefit
if the user ends up clicking on each tab, but in cases where the user chooses not to open
other tabs, this mode is far from optimal.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8783
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. SetupDefaults: tabAdvanced (Delay 1secs)
7. RefreshColors
8. BindTab: tabAdvanced (Delay 1secs)
9. tabAdvanced clicked
Postback - Good
This approach is nearly the best for the initial loading. This is due to the fact that only
the displayed tab is rendered. The reason it has a slightly larger render size is the script
that ASP.NET injects for the postback handler. The Callback method has no postback
script, for the only controls on the page that would do a postback are the buttons, and
they are submit buttons. In a real application, this difference most likely will not be
present, since there will usually be some other control that needs postback logic.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8047
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
7. >>> POSTBACK - Size: 1440
8. >>> Render Size: 9906
9. SetupDefaults: tabGeneral
10. SetupDefaults: tabAdvanced (Delay 1secs)
11. RefreshColors
11
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
12. BindTab: tabAdvanced (Delay 1secs)
Callback – Best
Like the postback rendering mode, this mode only renders the displayed tab, therefore
the size of the rendering size is much smaller. For reasons mentioned in the Postback
description, its size is slightly smaller than the Postback.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 7618
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
7. >>> CALLBACK - Size: 65
** 8. SetupDefaults: tabAdvanced (Delay 1secs)
** 9. RefreshColors
** 10. BindTab: tabAdvanced (Delay 1secs)
11. >>> Render Size: 1281
Partial Rendering – Bad
The rendering mode for the tabstrip for the partial rendering sample is using Postback.
As stated above, the postback rendering size is a little larger than callback. This mode is
slightly larger than postback, due to the markup necessary to enable partial rendering.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8633
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
** 7. >>> POSTBACK - Size: 4949
** 8. SetupDefaults: tabGeneral (Delay 1secs)
** 9. SetupDefaults: tabAdvanced (Delay 1secs)
** 10. RefreshColors
** 11. BindTab: tabAdvanced (Delay 1secs)
** 12. >>> Render Size: 5616
Stage 3 – Tab Click - Request
This stage measures the payload size from the client request to the server.
All Client – Best
Obviously, the mode that rendered all of its contents to the client on the initial load will
offer the best performance for the ensuing tab-clicks. The real question is, was the
slower page load worth the instant ability to view other tabs?
12
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
N/A
Postback - Worst
A postback causes the entire client-side elements to be posted to the server, which is
more information than we need in most cases*.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8047
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
7. >>> POSTBACK - Size: 1440
8. >>> Render Size: 9906
9. SetupDefaults: tabGeneral
10. SetupDefaults: tabAdvanced (Delay 1secs)
11. RefreshColors
12. BindTab: tabAdvanced (Delay 1secs)
Callback – Good
The only information posted to the server for this request is the tab which we are
retrieving. This allows for our payload to be really small. The only mode that beats it is
all, which doesn’t make the request at all.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 7618
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
7. >>> CALLBACK - Size: 65
** 8. SetupDefaults: tabAdvanced (Delay 1secs)
** 9. RefreshColors
** 10. BindTab: tabAdvanced (Delay 1secs)
11. >>> Render Size: 1281
Partial Rendering - Worst
Partial rendering uses postbacks, therefore it is the same as the Postback mode. A
postback causes the entire client-side elements to be posted to the server, which is more
information than we need in most cases *.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8633
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
13
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
** 7. >>> POSTBACK - Size: 4949
** 8. SetupDefaults: tabGeneral (Delay 1secs)
** 9. SetupDefaults: tabAdvanced (Delay 1secs)
** 10. RefreshColors
** 11. BindTab: tabAdvanced (Delay 1secs)
** 12. >>> Render Size: 5616
Stage 4 – Tab Click – Server Processing
This stage measures the amount of server-side processing necessary to facilitate the
request for the new tab.
All Client - Best
Obviously, the mode that rendered all of its contents to the client on the initial load will
offer the best performance for the ensuing tab-clicks. The real question is, was the
slower page load worth the instant ability to view other tabs?
N/A
Postback - Worst
The request for the clicked tab’s information causes the entire page to be processed
again.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8047
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
7. >>> POSTBACK - Size: 1440
8. >>> Render Size: 9906
9. SetupDefaults: tabGeneral
10. SetupDefaults: tabAdvanced (Delay 1secs)
11. RefreshColors
12. BindTab: tabAdvanced (Delay 1secs)
Callback – Good
Only the page’s init method is called. From there a call is made to the callback handler
which simply processes the methods required to render the requested tab.
1. InitializeNonTabControls
2. BindPage
14
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
3. >>> Render Size: 7618
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
7. >>> CALLBACK - Size: 65
** 8. SetupDefaults: tabAdvanced (Delay 1secs)
** 9. RefreshColors
** 10. BindTab: tabAdvanced (Delay 1secs)
11. >>> Render Size: 1281
Partial Rendering - Bad
Similar to the Postback mode, the entire page is processed on the server in order to serve
up the new tab. The difference with the postback is that partial rendering short-circuits
the final stages of the postback in order to send only the necessary information back.
One could argue that this additional processing to parse only the necessary info out of
the response would be more processing than the postback, however, I have not
investigated to determine if this is so.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8633
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
** 7. >>> POSTBACK - Size: 4949
** 8. SetupDefaults: tabGeneral (Delay 1secs)
** 9. SetupDefaults: tabAdvanced (Delay 1secs)
** 10. RefreshColors
** 11. BindTab: tabAdvanced (Delay 1secs)
** 12. >>> Render Size: 5616
Stage 5 – Tab Click - Payload
This stage measures the size of the payload sent down to the client that requested a new
tab.
All Client - Best
Obviously, the mode that rendered all of its contents to the client on the initial load will
offer the best performance for the ensuing tab-clicks. The real question is, was the
slower page load worth the instant ability to view other tabs?
N/A
Postback – Worst
15
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
The contents of the entire page are marshaled back to the client.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8047
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
7. >>> POSTBACK - Size: 1440
8. >>> Render Size: 9906
9. SetupDefaults: tabGeneral
10. SetupDefaults: tabAdvanced (Delay 1secs)
11. RefreshColors
12. BindTab: tabAdvanced (Delay 1secs)
Callback – Good
Only the html for the new tab is pushed to the client.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 7618
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
7. >>> CALLBACK - Size: 65
** 8. SetupDefaults: tabAdvanced (Delay 1secs)
** 9. RefreshColors
** 10. BindTab: tabAdvanced (Delay 1secs)
11. >>> Render Size: 1281
Partial Rendering – Bad
The html for the new tab, plus the updated viewstate, plus some additional markup outside the tab is sent down.
1. InitializeNonTabControls
2. BindPage
3. >>> Render Size: 8633
4. SetupDefaults: tabGeneral
5. BindTab: tabGeneral (Delay 1secs)
6. tabAdvanced clicked
** 7. >>> POSTBACK - Size: 4949
** 8. SetupDefaults: tabGeneral (Delay 1secs)
** 9. SetupDefaults: tabAdvanced (Delay 1secs)
** 10. RefreshColors
** 11. BindTab: tabAdvanced (Delay 1secs)
** 12. >>> Render Size: 5616
* The use case that is expected to be used for most tabstrip pages is one that simply
breaks up the page. One could envision a use case that functions like a wizard, where the
results from the previous tab are needed to render the following tab. In this scenario, a
postback, partial rendering, or some additional properties for a callback are required.
16
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
** These events and numbers are actually hardcoded in the client-side script. They were
obtained by using the debugger in VS.NET along with the use of Fiddler.
17
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Chapter 4: Sample Code
The purpose of this chapter is to discuss the code behind the sample. This section will
not cover the code used to capture the statistical information.
Markup
<table><tr>
<td colspan="2" class="header"><asp:Label ID="lblTitle" runat="server"></asp:Label></td>
</tr><tr>
<td><asp:Label ID="lblPageName" runat="server" Text="Page Name" /></td>
<td><asp:TextBox ID="txtPageName" runat="server" Text="Default Name"></asp:TextBox></td>
</tr></table>
…
<DNN:DNNTabStrip id="MyDNNTabStrip" SelectedIndex="0" runat="server"
DefaultLabel-CssClass="tablabel" DefaultLabel-CssClassSelected="tablabelselected"
DefaultLabel-CssClassHover="tablabelhover" DefaultContainerCssClass="tabcontainer"
CallbackStatusFunction="statusFunc" TabClickFunction="tabClick"
WorkImage="images/dnnanim.gif" >
<dnn:DNNTab Label-Text="General" Label-ImageUrl="images/object.gif" ID="tabGeneral"
runat="server">
<table><tr>
<td><asp:Label runat="server" ID="lblName">Name</asp:Label></td>
<td><asp:TextBox runat="server" ID="txtName"></asp:TextBox></td>
</tr><tr>
<td><asp:Label runat="server" ID="lblDesc">Description</asp:Label></td>
<td><asp:TextBox runat="server" Width="300px" ID="txtDesc"></asp:TextBox></td>
</tr></table>
</dnn:DNNTab>
<dnn:DNNTab Label-Text="Advanced" Label-ImageUrl="images/method.gif" ID="tabAdvanced"
runat="server">
<table><tr>
<td><asp:Label runat="server" ID="lblFont">Name</asp:Label></td>
<td><asp:TextBox runat="server" ID="txtFont">Default</asp:TextBox></td>
</tr><tr>
<td><asp:Label runat="server" ID="lblColor">Color</asp:Label></td>
<td>
<asp:DropDownList runat="server" EnableViewState="False"
ID="ddlColor"></asp:DropDownList>
</td>
</tr><tr>
<td><asp:Label runat="server" ID="lblLocation">Location</asp:Label></td>
<td>
<asp:DropDownList runat="server" EnableViewState="False" ID="ddlLocation"
DataSource='<%# Me.Locations %>'></asp:DropDownList>
</td>
</tr></table>
</dnn:DNNTab>
</DNN:DNNTabStrip>
18
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
There are two things that are worth noting about the markup. First, notice that we have
controls that will need to persist their values both inside and outside our tab control.
Second, notice that the controls found inside the DNNTab are marked up exactly the
same as they would be outside. The only difference being that in the design view you are
not able to click on the containing controls.
Note: I spent a considerable amount if time trying to allow for a better design time
experience, only to discover that unless I move my controls to the .NET 2.0 Framework,
the richer design time experience is not possible. At this point in time I do not want to
limit my audience to a 2.0 only implementation. I did try simply recompiling the
existing code in 2005 and was able to click on elements within the tabs. However, to be
able to click on an actual tab and have it change will require a little more programming
and will be addressed when I move to a .NET 2.0 only version.
CodeFile - Properties
The codefile contains properties that determine what rendering mode to use and
whether or not we are editing or adding a new record.
'retrieves tabrendermode from querystring
Public ReadOnly Property RenderMode() As TabRenderMode
Get
If Len(Request.QueryString("mode")) > 0 Then
Return CInt(Request.QueryString("mode"))
End If
Return TabRenderMode.All
End Get
End Property
'property to obtain the Id of the info object we are updating. -1 means new
19
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Public ReadOnly Property DataId() As Integer
Get
If Len(Request.QueryString("id")) > 0 Then
Return CInt(Request.QueryString("id"))
End If
Return -1
End Get
End Property
It also contains properties used to simulate sample data.
'if id is passed on the querystring (DataId) then assume we are editing an existing
‘record and pull the data from the dataservice layer, otherwise we are assuming a new
‘record, where the values are defaulted from the Info's constructor
Public ReadOnly Property PageData() As PageInfo
Get
If m_objInfo Is Nothing Then
If DataId > -1 Then
m_objInfo = DataServices.GetTabData(DataId)
Else
m_objInfo = New PageInfo
End If
End If
Return m_objInfo
End Get
End Property
'used to show declarative databinding to dropdown
Public ReadOnly Property Locations() As String()
Get
Return m_aryLocations
End Get
End Property
CodeFile – Event Handlers and Methods
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
SetUpRenderMode()
If Not Me.IsPostBack Then
'since we are populating all tabs in initial load both of these functions could be
'changed to InitializeControls and BindControls where both the tab controls and the
'non-tab controls perform their respective logic. However, I think it will be more
'helpful in comparing if all pages utilize the same function names
InitializeNonTabControls()
BindNonTabControls()
Else
MethodCalled(">>> POSTBACK - Size: " & Me.Request.TotalBytes.ToString, False)
End If
End Sub
The Page_Load event handler first calls a method to setup the page according to its
rendering mode. This includes setting the tabstrip’s TabRenderMode property, setting
the ratings dialog, and in the case of Partial Rendering, registering the Atlas scripts and
controls.
20
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
If the page is not considered a postback, notice how only the non-tab controls are
initialized and bound. Each tab has a SetupDefaults event that will be used to initialize
and bind the controls contained within the tab. If the page is rendering as part of a
postback we simply send the debugging information down noting the size of the request.
Protected Sub tabGeneral_SetupDefaults() Handles tabGeneral.SetupDefaults
MethodCalled("SetupDefaults: tabGeneral", False)
If tabGeneral.IsPostBack = False Then
MethodCalled("BindTab: tabGeneral", True)
'bind tab
Me.txtName.Text = PageData.name
Me.txtDesc.Text = PageData.description
End If
End Sub
Protected Sub tabAdvanced_SetupDefaults() Handles tabAdvanced.SetupDefaults
MethodCalled("SetupDefaults: tabAdvanced", True)
'always need to populate items since viewstate disabled
RefreshColors()
Me.ddlLocation.DataBind()
If tabAdvanced.IsPostBack Then
'if tab was rendered, we may need to re-select the listitems that were posted
'since we are not using the viewstate hack we need to reselect the listitem
FormUtil.SelectItem(Me.ddlColor, Request.Form(Me.ddlColor.UniqueID))
FormUtil.SelectItem(Me.ddlLocation, Request.Form(Me.ddlLocation.UniqueID))
Else
MethodCalled("BindTab: tabAdvanced", True)
'bind tab
Me.txtFont.Text = PageData.font
FormUtil.SelectItem(Me.ddlColor, PageData.color)
FormUtil.SelectItem(Me.ddlLocation, PageData.location)
End If
End Sub
The SetupDefaults event is used to assign our default values on each tab as it is
requested. One thing that should stick out is the fact that we are performing setup logic
for the tabAdvanced event regardless of the Tab.IsPostBack value. This is necessary
since we have disabled ViewState on our dropdowns. A form’s post will only contain the
selected value of a dropdown. It will not contain the other items in the list, nor will it
contain the text of the selected value. This requires the information to be stored
somewhere. We are choosing to be efficient programmers and not store this info in
ViewState, thus causing the data to be continually roundtripped. The only time I would
consider doing otherwise would be if the data required to populate our list was very
expensive to retrieve and even then I may cache the list server-side rather than causing it
to roundtrip. The other quirks found in this sample relating to dropdowns and viewstate
are discussed in this blog entry.
IMPORTANT UPDATE: Please refer to the end of this document for an improved way
to handle DropDownLists via the new PreLoadPostData event.
21
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
The last set of code we will discuss is how we persist the data from the page.
'this method is responsible for populating the info entity object with the
'posted values. Note: If a tab was not rendered on the client, the pre-existing
'values will be kept
Private Sub SaveForm()
MethodCalled("SaveForm", False)
Debug("==> Saving Non-Tab Controls...")
Me.PageData.pagename = Me.txtPageName.Text
If Me.MyDNNTabStrip.Tabs(0).IsPostBack Then
Debug("==> Saving tabGeneral...")
PageData.name = Me.txtName.Text
PageData.description = Me.txtDesc.Text
Else
Debug("==> tabGeneral NOT Rendered - Using Defaults...")
End If
If Me.MyDNNTabStrip.Tabs(1).IsPostBack Then
Debug("==> Saving tabAdvanced...")
PageData.font = Me.txtFont.Text
PageData.color = Request.Form(Me.ddlColor.UniqueID) 'viewstate disabled using request
PageData.location = Request.Form(Me.ddlLocation.UniqueID)
Else
Debug("==> tabAdvanced NOT Rendered - Using Defaults...")
End If
PersistData()
End Sub
'this method simulates the saving of the info to the database
'instead of calling the dataservices we simply output the results
'to the client
Private Sub PersistData()
MethodCalled("PersistData", True)
Debug("___________________________________________________")
Debug("--- This is the data to be sent to the database ---")
Debug("name=" & PageData.name)
Debug("description=" & PageData.description)
Debug("font=" & PageData.font)
Debug("location=" & PageData.location)
Debug("color=" & PageData.color)
Debug("___________________________________________________")
End Sub
The code to process the changes posted to the server first assigns all non-tab controls to
our PageInfo object. It then checks to see if each tab was rendered and therefore has it’s
IsPostBack property set. If it is set, we then use the values posted from the client. If it
has not been rendered, we leave the PageInfo object intact with either its originally
retrieved data in the case of an edit, or its defaulted data in the case of a new record.
The PersistData method simulates a call to the dataservice layer. All that is happening in
this sample is the debug information is populated with the pageinfo object’s values and a
delay is occurring since the second parameter to the MethodCalled method is true.
Note: In measuring the efficiency of code it would be helpful to determine how long
each task takes to run. When dealing with a sample like this where things like database
22
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
interactivity is simulated, a simple Thread.Sleep is used. The Methods Invoked window
will show (Delay 1secs) for each occurrence of this simulation.
TabRenderMode Conclusion
Now that we have some hard numbers on each of the modes in which you can render the
tabstrip, you may be asking which mode is the best. This chart summarizes my ratings of
each rendering mode during each phase.
All On Client Postback Callback Partial Rendering (Postback)
In order to answer the question, which mode is the best we need to consider at least two
use cases.
Use Case One: User Opens All Tabs
If you have a screen that requires the user to fill in data from each tab the majority of the
time, the All On Client mode may be the best. However, this may not always be the case.
Users seem to be more forgiving with a lot of short delays taking place after a user action
(tab click) than one large delay on the initial load. Also, if your server is under heavy
load it is often recommended to improve scalability by having a lot of smaller requests as
opposed to one long-running one to reduce contention.
Use Case Two: User Only Fills In Data From First Tab
If the screen typically only requires the first tab to be filled out, the last mode you would
want to use is the All On Client. The three other modes all have the same amount of
server processing. When it comes to the amount of data marshaled to the client they are
also pretty close, but the Callback rendering is the most efficient.
TabRenderMode - Final Thoughts
23
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Let face it, there are a lot of pages we develop where we have no idea which use case
above is more likely. It would be best to pick a rendering mode that handled both cases
well. This was the driving factor behind my developing of the DNNTabStrip. The
callback mode could arguably be the best mode for both use cases.
24
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Chapter 5: TabCallbackPostMode
Introduction
In this document’s introduction, I stated that the default behavior of the UpdatePanel
was to post the entire contents of the form to the server with each update. This allows
the update to contain logic relating to the currently input values on the client. There are
scenarios where this functionality is desirable. This chapter will discuss how the
DNNTabStrip control allows the developer to choose exactly what information should be
contained in the callback for each tab.
DNNTabStrip Wizard Sample
Like our previous discussion on the rendering modes, we will look at a sample
application to demonstrate each of four values the TabCallbackPostMode property
supports. In addition to discussing the four values (None, TabStrip, Form, and
DNNVariable), the sample will also show how you can programmatically interact with
the control on the client.
This sample may be run at
http://webcontrols.dotnetnuke.com/samples.net2/TabStripWizard.aspx
TabCallbackPostMode: Form
The default tab to display in our sample is the Welcome tab. It does not have its
TabCallbackPostMode is not set (therefore it defaults to None). It also does not contain
any controls that will post their data. However, if you look above the control you will
notice a Name textbox. Step 1 of our Wizard, has its tab’s TabCallbackPostMode set to
Form, meaning that the entire form’s contents (that would be posted in a normal
postback) will be sent, thus allowing Step 1 to know the value of the Name during its
rendering.
25
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Looking at our debug textbox we notice that the data posted indeed contains the name
(Your Name Here), along with all the other controls currently present on the form,
including ViewState.
__DNNCAPISCI=MyDNNTabStrip MyDNNTabStrip&__DNNCAPISCP=tabStep1
&__VIEWSTATE=dDwxNDA1NTEwMDc1OztsPE15RE5OVGFiU3RyaXA7Pj6kb8PZ1RN2vOPddX%2BDoBZLV%2FgcmQ%3D%3D
&txtName=Your%20Name%20Here2&txtMethods=
&__dnnVariable=%11MyDNNTabStrip_tabs%12tabWelcome%3D7%2CtabStep1%3D4%2CtabStep2%3D0%2CtabStep3%3D0%2Ct
abFinish%3D0&
Note: The __DNNCAPISCI and __DNNCAPISCP are used to identify the callback, see
the DotNetNuke ClientAPI Client Callback document for more details.
TabCallbackPostMode: TabStrip
26
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Notice that Step 1 contains a textbox and a dropdown list. Step 2’s
TabCallbackPostMode is set to TabStrip, which means that only the controls found
inside the tabstrip will be posted for its callback.
__DNNCAPISCI=MyDNNTabStrip
MyDNNTabStrip&__DNNCAPISCP=tabStep2&tabStep1:txtStep1=Type%20some%20text%20here&tabStep1:ddlColor=Red&
As you can see, the txtName, txtMethods, and ViewState data is not included this time.
27
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Step 2s output was affected by the previous tab’s inputs.
By default a callback will only be made once per tab. You may be asking what if the user
navigates back to Step 1 and changes the color? Will Step 2’s background be modified?
The answer, is it is up to you, but by default the answer is no, since we only do a callback
once per tab, however, in this example script has been added to reset the tab if the user
navigates backwards.
Now is probably a good time to discuss the code used to allow our Next >> and << Prev
buttons to function, along with our enabling of tabs, and of course, how we can cause a
tab’s contents to be pulled a second time.
The onclick client-side handler for the Next and Prev buttons is as follows
var m_oTS;
function getTabStrip()
{
if (m_oTS == null)
m_oTS = dnn.controls.controls['MyDNNTabStrip'];
return m_oTS;
}
function nextStep()
{
var oTS = getTabStrip();
var oTab = oTS.setSelectedIndex(oTS.selectedIndex += 1);
oTab.enabled = true;
updateTabs();
28
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
}
function prevStep()
{
var oTS = getTabStrip();
var oTab = oTS.setSelectedIndex(oTS.selectedIndex -= 1);
updateTabs();
}
The first step taken for each button is to obtain a reference to our tabstrip control. We
then either increment or decrement the currently selected index and assign a new one
with the setSelectedIndex method. Finally, the updateTabs method is called which we
review soon.
Note: You may be asking why we used a method to modify the selectedIndex instead of
updating the property directly. Ideally, I would have coded the control to support this,
but unfortunately browsers like Internet Explorer do not support the ability to hook up a
handler for a property. Other browsers like FireFox support getters/setters for
properties which would be ideal in this situation.
function updateTabs()
{
var oTS = getTabStrip();
if (oTS.tabIds.length - 1 > oTS.selectedIndex)
{
setTab(oTS.selectedIndex + 1, true); //enable next tab
//reset next tab, to allow it to be re-retrieved from callback...
//up to you whether you want your wizard to do this
oTS.resetTab(oTS.tabIds[oTS.selectedIndex + 1]);
if (oTS.tabIds.length - 1 > oTS.selectedIndex + 1)
setTab(oTS.selectedIndex+2, false); //disable tab following next
$('btnNext').disabled = false;
}
else
$('btnNext').disabled = true;
if (oTS.selectedIndex > 0)
$('btnPrev').disabled = false;
else
$('btnPrev').disabled = true;
}
function setTab(iIdx, bEnabled)
{
var oTS = getTabStrip();
var oTab = oTS.tabs[oTS.tabIds[iIdx]];
oTab.enabled = bEnabled;
oTab.assignCss();
return oTab;
}
By checking to see if the current selectedIndex is greater than the amount of tabs we can
properly enable or disable the next/prev buttons. Additionally, we can programmatically
enable and disable the following tabs. Notice how we simply set the enabled property on
the tab and call the assignCss to update its look to reflect any property changes. Finally
notice that we are calling the resetTab method to cause the tab to be reloaded each time.
29
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
TabCallbackPostMode: DNNVariable
Step 2 contained a button that when pressed asked the user to type in a value for the
MyValue variable.
If you are unfamiliar with how easy the ClientAPI enables the developer to pass variables
from client to server and vice versa, please review the DotNetNuke ClientAPI document.
Step 3 has its TabCallbackPostMode set to DNNVariable, meaning only the contents of
the variables will be marshaled to the server on its callback.
__DNNCAPISCI=MyDNNTabStrip
MyDNNTabStrip&__DNNCAPISCP=tabStep3&__dnnVariable=%11MyDNNTabStrip_tabs%12tabWelcome%3D5%2CtabStep1%3D
5%2CtabStep2%3D7%2CtabStep3%3D4%2CtabFinish%3D0%11MyValue%12A%20Value&
Note: In addition to MyValue variable’s contents being sent, all other values found in
the DNNVariable control are sent. In this case, the values the tabstrip uses to persiste its
state between postbacks.
30
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
TabCallbackPostMode: None
31
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
The final step has its TabCallbackPostMode set to None. The contents of what is posted
here is obviously the smallest and most efficient.
__DNNCAPISCI=MyDNNTabStrip MyDNNTabStrip&__DNNCAPISCP=tabFinish
TabCallbackPostMode Conclusion
This chapter focused on the ability of the DNNTabStrip control to choose the amount of
data it needs to handle each callback. This allows the developer to tailor his code to
allow for the most efficient means of using a callback. In the next chapter we will discuss
how the developer can tailor the server-side code to only process the needed events
within the page’s lifecycle.
32
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Chapter 6: CallBackType
Introduction
The ClientAPI currently supports two different types of Callbacks: Simple and
ProcessPage. The difference between these lies in how much of the default ASP.NET
page’s lifecycle is run before it is short-circuited. The following diagrams illustrate the
differences.
For a CallbackType of Simple the grayed out boxes are skipped.
33
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
For a CallbackType of ProcessPage, all the same events that happen in a normal
PostBack occur. The difference is in how much information is processed. For example,
only the tab’s HTML is rendered.
How To Choose
If the Simple method yields the most performance, an obvious question is why would
you ever want to choose ProcessPage? The answer to this lies in the contents of the tab
itself. If your controls require the events omitted from the Simple callback, then the only
choice is to use ProcessPage. The following flowchart is meant to assist you in your
decision.
34
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Viewstate is not something that is encouraged with the DNNTabStrip in callback mode.
To explain why, lets use a simple example. Lets say you have a tabstrip with two tabs,
each tab has a DropDownList on it with ViewState turned on. On initial load, the
viewstate is passed down for dropdown1 since it was rendered; however, dropdown2 was
not rendered, so no viewstate is present. The user then clicks on tab2 and it renders
dropdown2, but it does not include its viewstate. When the page is finally posted, the
code you use cannot expect the viewstate for dropdown2 to exist. The only way the
DNNTabStrip could have worked would be to render the entire page during tab2's
callback, thus allowing us to get a completely new viewstate to replace on the client.
Another option would be to include the page's existing viewstate in the callback and
somehow (I don't know) append the newly rendered tab's viewstate in a manner that
ASP.NET likes.
Simulating ViewState – PreLoadPostData Event
Earlier in the document you learned how to work with DropDownLists when no
viewstate was present. The method explained above required the use of the
Request.Form collection to access the selected values of a DropDownList. During some
proof of concept work done on the core, it was determined that it would be beneficial to
expose a new event. This event would fire just before the control’s LoadPostData event
occurred, hence the name PreLoadPostData. An example of how this works is found in
the TabStripChildControls sample.
Private Sub tabDropDownLists_SetupDefaults() Handles tabDropDownLists.SetupDefaults
If tabDropDownLists.IsPostBack = False Then
35
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
'If this is the first time the tab is loaded, we need to set it up
PopulateDropDownLists()
End If
End Sub
'We are populating the dropdowns to simulate viewstate. This event is only fired if
'a tab has been rendered to the client. Shortly after this event the LoadPostData
'event of the dropdowns will be called as part of the ASP.NET lifecycle.
'If the DropDown has items at this point, things like SelectedValue and SelectedItem
'will function.
Private Sub tabDropDownLists_PreLoadPostData() Handles tabDropDownLists.PreLoadPostData
PopulateDropDownLists()
End Sub
Private Sub PopulateDropDownLists()
Me.ddlDynamic1.Items.Add(New ListItem("Dynamic1Text", "Dynamic1Value"))
Me.ddlDynamic1.Items.Add(New ListItem("Dynamic2Text", "Dynamic2Value"))
End Sub
Private Sub btnDDLSave_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles btnDDLSave.Click
'The Static dropdownlist does not require the use of viewstate, the values are
'persisted with the aspx markup. However, the dynamic dropdown also works now
'that we populated the items in the PreLoadPostData event.
txtDropDowns.Text = "ddlStatic SelectedValue=" & ddlStatic.SelectedValue & vbCrLf & _
"ddlDynamic SelectedValue=" & ddlDynamic1.SelectedValue
End Sub
In some circumstances the cost to obtain the list of items to fill the dropdown with each
postback may be high. Therefore, it would be preferable to store its state somewhere,
perhaps even on the client. Further research needs to be done to determine the
feasibility of merging viewstate. However, even if this is possible, it may not end up
being the approach recommended. It is also possible to persist values across postbacks
utilizing the ClientAPI’s setVar/getVar. This would have the advantage of allowing us to
be able to update the dropdown’s state from the client. Something that would be highly
desirable if we utilized populate on demand for the list. At the time of the writing of this
document, it is assumed that should such a case come up, the developer would persist
the dropdown’s state manually.
36
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Additional Information
The DotNetNuke Portal Application Framework is constantly being revised and
improved. To ensure that you have the most recent version of the software and this
document, please visit the DotNetNuke website at:
http://www.dotnetnuke.com
The following additional websites provide helpful information about technologies and
concepts related to DotNetNuke:
DotNetNuke Community Forums
http://www.dotnetnuke.com/tabid/795/Default.aspx
Microsoft® ASP.Net
http://www.asp.net
Open Source
http://www.opensource.org/
W3C Cascading Style Sheets, level 1
http://www.w3.org/TR/CSS1
Errors and Omissions
If you discover any errors or omissions in this document, please email
[email protected]. Please provide the title of the document, the page number
of the error and the corrected content along with any additional information that will
help us in correcting the error.
37
Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.
Appendix A: Document History
Version Last Update Author(s) Changes
1.0.0 August 11, 2006
Jon Henning Creation
1.1.0 February 2, 2007
Jon Henning Added Chapter 6
Updated Chapter 4