38
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

WebControls - TabStrip

Embed Size (px)

DESCRIPTION

test description

Citation preview

Page 1: WebControls - TabStrip

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

Page 2: WebControls - TabStrip

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.

Page 3: WebControls - TabStrip

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.

Page 4: WebControls - TabStrip

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

Page 5: WebControls - TabStrip

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

Page 6: WebControls - TabStrip

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

Page 7: WebControls - TabStrip

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.

Page 8: WebControls - TabStrip

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

Page 9: WebControls - TabStrip

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

Page 10: WebControls - TabStrip

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

Page 11: WebControls - TabStrip

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

Page 12: WebControls - TabStrip

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?

Page 13: WebControls - TabStrip

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

Page 14: WebControls - TabStrip

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

Page 15: WebControls - TabStrip

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

Page 16: WebControls - TabStrip

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.

Page 17: WebControls - TabStrip

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.

Page 18: WebControls - TabStrip

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>

Page 19: WebControls - TabStrip

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

Page 20: WebControls - TabStrip

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.

Page 21: WebControls - TabStrip

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.

Page 22: WebControls - TabStrip

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

Page 23: WebControls - TabStrip

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

Page 24: WebControls - TabStrip

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.

Page 25: WebControls - TabStrip

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.

Page 26: WebControls - TabStrip

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

Page 27: WebControls - 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.

Page 28: WebControls - TabStrip

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();

Page 29: WebControls - TabStrip

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.

Page 30: WebControls - TabStrip

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.

Page 31: WebControls - TabStrip

30

Copyright © 2003-2005 Perpetual Motion Interactive Systems, Inc. All Rights Reserved.

TabCallbackPostMode: None

Page 32: WebControls - TabStrip

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.

Page 33: WebControls - TabStrip

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.

Page 34: WebControls - TabStrip

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.

Page 35: WebControls - TabStrip

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

Page 36: WebControls - TabStrip

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.

Page 37: WebControls - TabStrip

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.

Page 38: WebControls - TabStrip

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