How to Make Your ASP.NET Third Party Component 10x Faster


 

1. Abstract

The following document will explore the basics of enhancing 3rd party ASP.NET components performance by leveraging the Empty Client (an ASP.NET extension) pipeline.

1.1 What is the Empty Client?

This architecture is an emerging open source methodology which offers a different approach to architecting, developing and deploying AJAX applications. In order to shed some light on this methodology, we will compare it to the classic Thin and Thick (also referred to as Fat or Smart) client approach and to traditional AJAX structures. Empty Client offers a new balance between the Thin and Thick client approaches and a new channeling of the AJAX calls.

The Thin client model communicates with a central processing server, meaning there is little hardware and software installed on the user's machine. This allows all end users' systems to be centrally managed with software deployed on a central server location, as opposed to being installed on each individual system. This is usually used in places where it would create a major headache for IT to both deploy and maintain so many user stations. In contrast, a Thick client will provide users with more features, graphics and choices, thereby expanding the opportunities to make the applications much richer. Unlike Thin clients, Thick clients do not rely much on a central processing server because most of the processing is done locally on the user system, and the server is accessed primarily for storage and data retrievals purposes. For that reason, Thick clients often are not well-suited for public environments. To maintain a Thick client, IT needs to maintain all systems for software deployment and upgrades, rather than just maintaining the applications on the server. Additionally, Thick clients often require operating specific plug in, again posing more work and limitations for deployment. The trade-off is a more robust and local computing environment.

The Empty Client approach succeeds for the first time in web and cloud to combine the best of both worlds - the desktop and web environments or Thick and Thin client approaches and enhance them with AJAX. With the Empty Client approach an optimized protocol generates and extends server-side power, typically achieved with Thin client, and make it available for data centric, customizable and scalable web applications, typically achieved with Thick Client. Furthermore, the Empty Client leverages the client's processing power to render the UI and to activate any of the server's instructions. The Empty Client uses asynchronous refreshes, and a JavaScript-based engine to communicate with the server. Instead of communicating at the component level in a scattered way, it communicates the incremental updates, asynchronously through one central pipeline. What this means is that rather than open numerous routes to the server, it channels all communication through its centrally controlled pipeline; essentially, Empty Client relies on AJAX but does all the plumbing under the hood.

image1.gif

VWG centralized Ajax pipeline

It also achieves the highest scalability and performance that, in the past, were enabled only with the Thick client approach. It is called the Empty Client because it doesn't run any logic or data manipulation on the client, it doesn't expose data or logic, nor does it require exposing web services consumed by the client, which is a very common non-secure practice on traditional AJAX development methods. It is also referred to as Clever Client because with this approach the UI control's process is an integral part of the control just like a single layered desktop control only divided into the control rendering part (on the client) and the control's logic part (on the server); it executes on top of traditional and standard web platforms and creates the feeling of a native client-side application that usually run as Thick or Fat client only with a Thin client footprint. The Empty Client differs from the Thin client also because it runs on any plain browser with no plug-ins and it does not transfer bitmaps. Thus, by allowing central computing with the strong processing power that clients typically have today the Empty Client really offers the best of both worlds.

1.2 Audience

This document is targeted towards software architects and advance developers who would like to learn the basics of ASP.NET controls upgrade to become Empty Client native controls.

1.3 Objectives

This document describes the general process of migration; reading this document should make it possible for the reader to estimate the amount of work required to wire-up and transform an existing ASP.NET control into a native, functional equivalent Empty Client control.

Important Note: This document does not replace a detailed developers' guide of the upgrade tasks, although, it should provide general understanding of how Empty Client controls are built, what parts are reusable when upgrading ASP.NET controls and what parts should be adjusted or recreated.

1.4 General and essential assumptions
  • This document assumes that the reader has the source code for the components you are migrating in and that you are legally allowed to use it.
  • This document assumes that the reader has basic knowledge on custom controls creation for the ASP.NET platforms.
  • This document assumes that the reader has some basic web architecture understanding as well as familiarity with the major different browsers on the market.

1.5 Empty Client standard development tool

Empty Client applications are coded using standard .NET languages (C#.NET/VB.NET) and utilize the productive proven VB6 and WinForms development paradigm to develop generic web applications including WYSIWYG form designer and a web designated theme designer which makes it possible to customize web controls look & feel as well as behaviors.

1.6 Web / ASP.NET extension

Empty Client replaces the pipeline protocol and creates a new pipeline; however purely based on the standard ASP.NET technology. It uses ASP.NET including its base objects (Server, Session, Application, Request and Response), deployed on standard IIS (no server installation required) and the code is parsed by the standard .NET CLR.

This constitutes the following benefits:

  • Interactive with any ASP.NET application (including mutual containment)
  • Any ASP.NET control can be Wrapped in by a click of a button
  • Interacts with any other web technology
  • Reduces risks in terms of infrastructures and use known and proven MS underlying technologies.
  • XCopy deployment
2. Why bother upgrading controls to native Empty Client?

2.1 Increasing demand for VB 6.0 and WinForms upgrade

Plain Web is the most preferred deployment model due to a centralized application deployment efforts and the ability to consume application everywhere.

WinForms applications are starting to find their ways to the web. The Empty Client is the only technology out there that can run WinForms compliant code over web without having to rewrite the code and being able to leverage almost 100% of the legacy code investments.

The source WinForms applications often use third party controls so the migration process often needs to supply replacements for those controls. The migration project's engineers and architect always prefer a native Empty Client control over wrapping-in an external control.

Recent Microsoft announcements to stop supporting VB 6.0 have increased the market request for VB 6.0 application modernization. However they all want to end-up with a web application rather than a desktop one â€" even if based on .NET. Here too, the source VB 6.0 apps often use third party controls and so that the migration process often needs to supply replacements for those controls. The migration project's engineers and architect always prefer a native Empty Client control over wrapping-in an external control.

2.2 Rapid development paradigm

Using the most proven and intuitive rapid development patterns, Empty Client â€" Visual WebGui framework makes it possible for developers from a wider skill levels range to develop complex high-end line of business applications.

RAD Features:
  • Truly WYSIWYG, drag & drop Form based designer
  • Simple data-binding using Visual Studio standard desktop-like UI
  • Controls and themes point & click designer
  • Events handling as simple as VB 6.0 or WinForms development

And many more...

2.3 Performance (benchmarked)

Empty Client unique runtime and pipeline, runs up to 10 times faster than any other traditional ASP.NET components which can be concluded by the following graphs collected by performance specialist MS MVP Mr. Wiktor Zychlah:
image2.gif

Received and sent data

image3.gif

Requests per second

2.3.1 Low bandwidth consumption

Having balanced presentation state both on the client and on the server, Empty Client apps' optimized protocol transfers much less data between the client and the server. Latest benchmarks indicate consumption of around 10% of traditional ASP.NET Ajax based equivalent applications.

2.3.2 Largest number of concurrent users

Empty Client state-full architecture, result in much less CPU consumption on the server (< 50%) due to the ability of the server to immediately run the event handling code on the live state. Furthermore, the fact that there is no need for mass objects' constructions and disposals on the server dramatically reduced the CPU usage.

2.4 Security

The Empty Client paradigm is secured by-design due to the fact that nothing except for UI commands and one static kernel is downloaded to the client. This means that:

  • No sensitive/hidden data is sent to the client. Neither the infrastructure nor the developers can perform security violations by sending sensitive data to client machines.
  • The server exclusively handles interaction with data and other services.
  • The client is responsible to render UI and send events to the server; in any case it can never control the server's behavior.
  • Each client request is validated by the single layer server code which constitutes a single point access control center.
2.5 Scalability and deployment economy

Empty Client is fully scalable and redundant across web farms due to a unique capability of enabling serialization of the entire state model into a floating state server (preferably cluster DB based state server). A single IIS server can server between 200-400 concurrent users and even more since it reduces the CPU usage dramatically.

2.6 Multiple presentation layers support

One of the outcomes of Empty Client architecture is a generic object model that is completely separated from UI rendering. This architecture which is often described as decoupled presentation layer provides the ability to render the UI and consume the application practically from any device which can receive and send XML.

The application itself runs on the server and acts on objects containing only metadata and data and the client only renders the UI as reflected from the current application state on the server.

2.7 Cloud optimized architecture

Empty Client enables the heaviest organization's desktop apps on the cloud with no UI compromises and at no-cost. Being a highly optimized server-centric architecture; Empty Client has high value and support the model of cloud computing scenarios in terms of compatibility and optimizations considerations.

2.8 Controls & Themes design and extensibility model

Being pure web architecture, Empty Client utilizes the web server and client technologies underneath; therefore, it is possible to create new controls based on the same concepts and set of tools. Customization and extensibility features:

1. Theme designer - enables visual point & click editing of themes/skins.
2. Control level designer - enables visual point & click editing & creation of new controls (inherited or from scratch)
3. Wrapping in new ASP.NET based controls (i.e. Infragistics, Telerik, DevExpress, ComponentOne, Syncfusion etc.)
 
3. Empty Client control

3.1 Controls' structure

An Empty Client control consists of:
  • Server-side part written in .NET and represents its entire API and set of server-side events (which are the default ones in the Empty Client concept.
     
  • Client-side part written using browser client languages: JavaScript, CSS, XSLT and Images resources

    image4.gif

3.2 How does it work?

The following diagrams show the runtime flow of Empty Client.
The first one shows the flow of the initial request that the client performs to the server, while the second one shows the normal flow throughout the application run.

1. Initial Request Scenario 

image5.gif
 
  • The Kernel contains the controls' client codes and some common protocol mechanisms.
  • The Context object reside within the IIS/ASP.NET session and holds the relevant state of the currently active tree of controls according to the current shown state of the user in the application.
  • The server is responsible to serve the Kernel resources for download according to the specific requesting browser/device.
1. Runtime Flow Scenario 

image6.gif
 
  • At runtime, the client renders the deltas of the entire view using a combined XSLT assembled from all the common XSLTs and control specific XSLTs, according to the commands sent from the server.
     
    • The client sends over highly optimized queue of events according to which the server runs the relevant event handlers.

3.3 The server part of the control

3.3.1 Introduction

The server-side code of each control contains most of its code:

  • Rich set of event handlers
  • Desktop like set of properties
  • All sorts of Calculations
  • Data-binding code
  • Most of the validations
  • Render-Attributes code (part of the protocol - will be explained further in this document)
  • Designer specific code
     
    • ShouldSerzlize methods (code dom supportive)
    • "DesignTime" forked behaviors
    • Specific Editors and design behaviors (Located in separate classes)
3.3.2 Overview

Following is an edited (shortened) sample code from within Button.cs (a thorough description of each part follows this piece of code):

using System;
using System.Xml;
using System.Drawing;
using System.ComponentModel;
using System.Runtime.Serialization;
using Gizmox.WebGUI.Common.Interfaces;
using Gizmox.WebGUI.Common.Resources;
using Gizmox.WebGUI.Forms.Design;
using Gizmox.WebGUI.Common.Extensibility;
 
namespace Gizmox.WebGUI.Forms
{
   public enum ButtonStyle
   {
         Normal=0,
         Custom=1
   }
...

///<summary>
///
The Button control
///</summary>
[ToolboxItem(true)]
[ToolboxItemCategory("Common Controls")]
[ToolboxBitmapAttribute( typeof(Button), "Gizmox.WebGUI.Forms.Button.bmp")]
[DesignTimeController("Gizmox.WebGUI.Forms.Design.ButtonController, ..., ...")]
[ClientController("Gizmox.WebGUI.Client.Controllers.ButtonController, ...,...")]
[MetadataTag(WGTags.Button)]
[SilverlightControl("Gizmox.WebGUI.Silverlight.Controls.BindableFlat...,... ")] [SilverlightControl("Gizmox.WebGUI.Silverlight.Controls.Bindable...,...,...")]
   public class Button : Control, IButtonControl
   {
         ///<summary>
      /// Reference to the images list
         ///</summary>
        private ImageList mobjImageList = null;
        ...    
          ///<summary>
         /// Creates a new <see cref="Button"/> instance.
         ///</summary>
         public Button()
         {
         }

         ///<summary>
         /// Fires an event.
         ///</summary>
         ///<param name="objEvent">event.</param>
        protected override void FireEvent(IEvent objEvent)
        {
            // disable button after click when ClickOnce property is true
            if (this.ClickOnce && objEvent.Type == "Click")
            {
                this.EnabledInternal = false;
            }
            // invoke base method
            base.FireEvent(objEvent);
        }

         ///<summary>
         /// Renders the attributes to be sent to the client
         ///</summary>
         ///<param name="objContext">The current context</param>
         ///<param name="objWriter"></param>
protected override void RenderAttributes(IContext objContext, IAttributeWriter objWriter)
         {
               base.RenderAttributes (objContext, objWriter);

               // add attributes to conterol element
               objWriter.WriteAttributeString(WGAttributes.Text,Text);

               // Set text align attribute
objWriter.WriteAttributeString(WGAttributes.TextAlign,
menmTextAlign.ToString());

               // Get image.
               ResourceHandle objImage = this.Image;

               if (objImage != null)
               {
                     // add attributes to control element
objWriter.WriteAttributeString(WGAttributes.Image,
objImage.ToString());
objWriter.WriteAttributeString(WGAttributes.ImageAlign,
ImageAlign.ToString());
objWriter.WriteAttributeString(WGAttributes.
TextImageRelation,
((int)menmTextImageRelation).ToString());
            }

               else
               {
objWriter.WriteAttributeString(
WGAttributes.TextImageRelation, "0");

               }

               // render context menu if needed
               if(DropDownMenu!=null)
               {
                     DropDownMenu.RegisterMenu(this);
objWriter.WriteAttributeString(WGAttributes.DropDown,
DropDownMenu.Guid.ToString());
               }

              // render ClickOnce attribute
            if (ClickOnce)
               {
objWriter.WriteAttributeString(
WGAttributes.ClickOnce, "1");
            }
         }

[DefaultValue(-1), RefreshProperties(RefreshProperties.Repaint), SRDescription("ListViewItemImageIndexDescr"), Localizable(true), SRCategory("CatBehavior")]
        public int ImageIndex
        {
           get
            {
                return mintImageIndex;
            }
            set
            {
                if (mintImageIndex != value)
                {
                    mintImageIndex = value;
                    mstrImageKey = string.Empty;
                    this.Update();
                }
            }
        }

         ///<summary>
         /// Gets or sets the text.
         ///</summary>
         ///<value></value>
         public override string Text
         {
               get
               {
                     return GetCommandText(base.Text);
               }
               set
               {
                     if(base.Text != value)
                     {
                           base.Text = value;
                           this.Update();
                     }
               }
         }

         ///<summary>
         /// Gets or sets the alignment of the image on the button control.
         ///</summary>
         [System.ComponentModel.DefaultValue(ContentAlignment.MiddleCenter)]
         public ContentAlignment ImageAlign
         {
               get
               {
                     return menmImageAlign;
               }
               set
               {
                     if(menmImageAlign!=value)
                     {
                           Update();
                     }
                     menmImageAlign = value;
               }
         }
         ...

         ///<summary>
        /// Code dom: Shoulds the serialize image.
        ///</summary>
        ///<returns></returns>
        protected bool ShouldSerializeImage()
        {
               return (mobjImage != null);
        }

         ...
}

Attributes

Above each control's server-side class there are a few attributes that describe the mapping of the different designers and tool-box items, Empty Client client-side resources tag name and mappings to other presentation layer's resources; i.e. the matching Silverlight client control.

Events

The FireEvent() function which overrides the base Control's method, maps the types of the events which are relevant for this control to the actual server event handlers that should be raise accordingly.

RenderAttributes

This method is part of the Empty Client protocol. It provides the set of properties that the client needs to receive in order to render or re-render this control entirely.

The first line of code in this method is the an invocation of the base class's RenderAttributes method since the "dynasty" of base classes (Control and Component) contain many common attributes which are not control specific.

In some controls there is a mode of partially rendering of the controls, this method is called RenderUpdatedAttributes, most of the events will not end up fully rendering the controls or even partially but rendering only the deltas according to the minimal set of changes required. This behavior is an integral part of the Empty Client client-server protocol algorithm.

Properties and Methods

The set of methods and properties define the UI logic/behavior and the component's API. Those methods and properties are similar in nature to a single layered control (such as WinForms).

Should Serialize Methods

Those are designer related properties, which define the Code DOM what properties should be serialized within the automatically generated InitializeComponents code and in what conditions.

3.3.3 Summary

The server piece of code is the one responsible for most of the controls behavior, the only parts that are not included in this code are the parts where the controls are actually rendered on the browser and the JavaScript pieces of code which represent the client-side behaviors of the controls and the code that fires the events that are possible to raise from the controls.

3.4 The client part of the control

3.4.1 Introduction

The client-side code of each control consists of:

  • Multi-browser supportive JavaScript code (represents client behaviors).
  • Multi-browser supportive CSS (represents a dynamic styling format).
  • Multi-browser supportive XSLT document (represents the transformation to plain HTML).
3.4.2 Overview
  • The client-side code of each control contains the following pieces of code:
     
  • Multi-browser supportive JavaScript code (represents client behaviors); follows is ButtonSkin.Button.js

    function Button_KeyPress(strGuid,objEvent)
    {    
        // Get the pressed key
        var intKeyCodeWeb_GetEventKeyCode(objEvent);

        // Check if enter or Spacebar was pressed.   
        if (intKeyCode==mcntEnterKey || intKeyCode==mcntSpaceKey)
        {
          //raise the click event
    Events_Click(strGuid,Data_IsCriticalEvent(strGuid,mcntEventClickId));
        }
    }

     

    • The reason for having only a few lines of code is that most of the controls' common JavaScript code exists within common behaviors files. The entire JavaScript is collected when the client approaches the server for the first time into one large and size optimized JavaScript code file.
       
    • The naming format of function, i.e. Button_KeyPress reflects the name of the file '_' its descriptive name (significant functionality description). This way the line:

      Events_Click(strGuid,Data_IsCriticalEvent(strGuid,mcntEventClickId));

      Invokes the method Click within the Events code file.
       
  • Multi-browser supportive CSS (represents a dynamic styling format); follows is an edited and shortened version of ButtonSkin.Button.css.

    Button-FontData
    {
          [Skin.Foreground];
          [Skin.Font];
    }

    .Button-FlatControl
    {
          width:100%;
          height:100%;
          border:transparent 1px solid;
          outline:none;
    }
    ...

    .Button-Control_Disabled .Button-TopRight
    {
          [Skin.RightTopDisabledStyle];
    }
     
    .Button-Control_Disabled .Button-Right
    {
          [Skin.RightDisabledStyle];
    }

     

    • It is rapidly noticeable that the file is assembled of standard CSS classes and parameters.
    • The parameters are collected and filled by the first time that the client approaches the server.
    • All of the CSSs together are served within a single flat and size optimized CSS file.
     
  • Multi-browser supportive XSLT document (represents the transformation to plain HTML); follows follows is an edited and shortened version of ButtonSkin.Button.xslt:

    <?xmlversion="1.0"encoding="UTF-8" ?>
    <xsl:stylesheetversion="1.0"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          xmlns:WC="wgcontrols">

     <!-- Draws the content of a flat button -->
    <
    xsl:templatematch="WC:Tags.Button[@Attr.CustomStyle='F']"mode="modContent">

        <!-- Apply button attributes -->
        <
    xsl:call-templatename="tplApplyButtonAttributes" >
          <xsl:with-paramname="prmButtonClass"select="'Button-FlatControl'" />
        </xsl:call-template>

        <!-- Draw button frame -->
        <
    xsl:call-templatename="tplDrawFrame">
          <xsl:with-paramname="prmLeftFrameWidth"select="0"/>
          <xsl:with-paramname="prmRightFrameWidth"select="0" />
          <xsl:with-paramname="prmTopFrameHeight" select="0"/>
          <xsl:with-paramname="prmBottomFrameHeight" select="0"/>
          <xsl:with-paramname="prmCenterContent"select="."/>
          <xsl:with-paramname="prmApplyPedding"select="1" />
        </xsl:call-template>

     </xsl:template>

     <!-- Draws the content of a normal button -->
    <
    xsl:templatematch="WC:Tags.Button[not(@Attr.CustomStyle)]"
    name="tplMatchButtonNormal"mode="modContent">
        ...
     </
    xsl:template>

     <!-- Disable styles that are not used in button -->
     <
    xsl:templatematch="WC:Tags.Button"mode="modApplyStyle">
        <xsl:call-templatename="tplApplyStyles" >
          <xsl:with-paramname="prmBackground"select="0" />
        </xsl:call-template>
     </
    xsl:template>

    </xsl:stylesheet>

3.4.3 Summary

Empty Client control consists of a single layered server-side code and client JavaScript, XSLT and CSS according to need.

4. Upgrade of ASP.NET based controls to Empty Client

4.1 Introduction

In this section the general process of migrating ASP.NET controls into Empty Client will be described. The following steps will be described and further explained:

Copy the server code into a Visual WebGui .cs file.

Analyze the control and move all the UI logic to the server.

Create the client XSLT, JavaScript and CSS based on the current rendering model of the ASP.NET control.

4.2 Overview

Step 1: Copy the server code into a Visual WebGui .cs file start adding the RenderAttributes method

Open a Visual WebGui project and then a new class and copy the ASP.NET server code to it. Most of the server UI behavior code is reusable in this level.

The object model should align to the Empty Client object model, which is actually an extended form of the WinForms object model. For instance, each component should inherit the "Component" class if it has no UI expression or inherit "Control" class if it has a UI expression. This object model is best described here: http://msdn.microsoft.com/en-us/library/system.windows.forms.aspx.

Furthermore, in this step should start planning and adding the RenderAttributes method, the basic purposes of this method and a small sample is found under the "Server-side part of the control" section of the "Control's structure" chapter above.

Step 2: Analyze the control and move all the UI logic to the server

Although it is possible to add client-side code into Visual WebGui or use the client-client invocation methodology it is still a server centric architecture by-default. In order to preserve the secured and responsive nature of Empty Client native controls, it is much recommended to move at least all of the non-frequent events to the server and add support for client-client invocation mechanism in order to provide the end developer the ability to choose between client handled event code and server handled event code.

Step 3: Create the client XSLT, JavaScript and CSS based on the current rendering model of the ASP.NET control

This step should be assembled of mostly reused code, resources and layouts. There are many helper methods, templates and patterns which can make the creation of XSLT or adjustment of existing XSLTs and HTMLs to render the standard HTML layout of the controls in Visual WebGui. Also the creation of specific JavaScript code and add CSS classes is much easier and straight forward using those services.

XSLT

Adjusting the existing XSLT and HTMLs should be transformed into Visual WebGui compliant XSLT. Applying many of the control's properties will be a very simple task using the common templates in Visual WebGui as shown in the code bellow:

...   
<!--
Draw the button content -->
<
xsl:templatematch="WC:Tags.Button"name="tplMatchButtonFrameCenterContent"mode="modFrameCenterContent">    <divclass="Common-Strech">
      <xsl:attributename="style">       
        <xsl:call-templatename="tplApplyStyles" >
          <xsl:with-paramname="prmBorder"select="0" />
          <xsl:with-paramname="prmBackground"select="1" />
          <xsl:with-paramname="prmFont"select="0" />
          <xsl:with-paramname="prmCursor"select="0" />
        </xsl:call-template>
        <
xsl:call-templatename="tplApplyPaddings"/>
        overflow:hidden;
      </xsl:attribute>
...

In the Button's control partial XSLT above; two common templates are being used (applied) from the Visual WebGui's available common templates:

  • Styles (tplApplyStyles) applying the dynamic definitions within the style HTML attributes which are required for styling aspects in the button contents.
  • Padding (tplApplyPaddings) applying the dynamic definitions within the style HTML attributes which are required for padding aspects in the button contents.
JavaScript

In the process of choosing what existing code is reusable, you should think of the following guidelines:
  1. ASP.NET Ajax callbacks should be replaced with Visual WebGui's standard pipeline calls
  2. It is recommended that the Visual WebGui naming standards would be kept in order for the internal kernel compiler to perform an efficient variables scoping.
  3. It is highly recommended to replace common libraries with Visual WebGui internal services (samples are shown below).
The following code is taken from ListView JavaScript file and demonstrates some sample Visual WebGui client services which can and should be used:

function ListView_Click(strGuid,strId,objWindow,objEvent)
{
    // Get the pressed key
    var intKeyCode = Web_GetEventKeyCode(objEvent);
 
    // Executig selection of list item
ListView_Select(strGuid, strId, objWindow, Web_IsShift(objEvent), Web_IsControl(objEvent), true);

    if(Data_IsCriticalEvent(strGuid,mcntEventSelectionChangeId))
    {
// Handles the click event and forces raise        Web_OnClick(objEvent,objWindow, true);
    }
 }

In the code sample above:

  • Web_GetEventKeyCode method extracts the codes of the keys pressed from the JavaScript event object.
  • Data_IsCriticalEvent method verifies if this event is considered a critical event according to the current server code and control's definitions.
    Web_OnClick method is responsible to raise an actual click event through Visual WebGui pipeline.
The next code sample shows a few other client-side JavaScript services:

function ListView_Select(strGuid,strId,objWindow,blnShiftKey,blnCtrlKey,blnSuspendRaiseEvents,intKeyCode)
{
   // Exit on disabled control
  if(Data_IsDisabled(strGuid)) return;

     // Get the multiselect attribute.
   var objNode = Data_GetNode(strGuid);
   var blnMultiple = Xml_IsAttribute(objNode,"Attr.Multiple","1");
  
List_Click(strGuid,strId,(blnMultiple?0:3),false,false,
objWindow,blnShiftKey,blnCtrlKey,blnSuspendRaiseEvents);
}

In the code sample above:

  • Data_IsDisabled method figures out if the control is disabled of not.
  • Data_GetNode method retrieves the updated xml node of a specified control from the "state behind" (client-side state).
  • XML_IsAttribute method checks the value of an attribute within the "state behind" (client-side state) xml node.

Like the services that have been demonstrated above, there many services to cover each and every JavaScript task including the interaction with the client-side state and Visual WebGui's unique events mechanism.

CSS

Existing CSSs can be reused almost as is, the only consideration here would be whether the imported control should be theme-able or not. If it is, the parameters method, as shown bellow should conform to Empty Client standards.

In the code sample bellow, taken from the ListView CSS file, it is shown that most of the CSS attributes are dynamically created by the server through the object model once the current theme is downloaded to the client. There are a few constant attributes:

ListView-Control
{
   [Skin.Border];
   [Skin.Background];
}

.ListView-FontData
{
   [Skin.Font];
   [Skin.Foreground];
}

.ListView-HeaderCell
{
   [Skin.HeaderNormalStyle];
}

.ListView-HeaderCell_Enter
{
   [Skin.HeaderHoverStyle];
}

.ListView-HeaderCell_Down
{
   [Skin.HeaderPressedStyle];
}

.ListView-HeaderSeperator
{
   width:[Skin.HeaderSeperatorWidth]px;
   [Skin.HeaderSeperatorNormalStyle];
   cursor: w-resize;
   overflow:hidden;
}

4.3 Summary

The transformation that an ASP.NET control should go through in order to become usable within Empty Client consists of reusing the client rendering parts, most of the layouts, JavaScript and CSS and creating the control's server-side code strongly based on the existing ASP.NET server-side code only as a Visual WebGui compliant object model (which is actually an extended form of WinForms object model)


Similar Articles