Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Sunday, December 14, 2008

Simplify Inline Editing using GridView, GridViewControlEmbedder ASP.NET AJAX Extender.

I created another nice ASP.NET AJAX extender for GridView.

With it's help you can enable inline editing for Grids in web pages relatively faster, comparing to time needed to implement this feature from scratch using pure JavaScript.

For example having the following GridView on the page:

image

You can add an extender that allows editing of values of cells right in place:

image

Extender has inner elements named "GridViewControlEmbedderColumn", each of this elements enabled inline editing for one column in the GridView. ColumnIndex attribute points to client side cell index - for example 0 will point to "First Name" column. ControlType can have one of several values. For now extender supports two types of embedded controls for cells - "TextBox" and "ComboBox". CssClass attribute is optional and if you set it to some css class it will be assigned to embedded control when it's created.

Extender itself has several important properties and events.

HoverCssClass - set here the css class that will be assigned to cell's in GridView when they are hovered (hover css class will work only for cells having embedded control assigned to them).

TargetControlID - set here ID of target GridView control, this extender should extend.

RowIdAttributeName - set here name that will be used as name for client side attribute when GridView rows are rendered. It is important to understand that values that will be entered into each cells are identified using column index and row id - some data-driven value that will identify row uniquely. The ID itself can be set in event handler for OnGridViewControlEmbedderRowReady event (see below).

OnGridViewControlEmbedderRowReady - subscribe to this event to set row IDs initial cell values for each row and cells in it before GridView renders. Client side script has to know this values to correctly populate/accumulate values that will be later available on server side after postback.

For the sample markup showed above this event handler will look like this:

image 

Lets review this code in more details.

First line of code just gets to the DataItem property of the GridView Row, in the sample I use XmlDataSource and this code allows to get to the original XPathNavigator to be able to retrieve values from the datasource for that row. It's important to mention that this event is raised for each row of GridView in synch with OnRowDataBound event raised originally by GridView. So in this event handler you can do the same manipulation over row/cells as you could in OnRowDataBound event handler.

Now there are two properties of EventArgs object that need to be set. These are e.RowID and e.CellValues.

Set some unique value to e.RowID (type of string) - this will be used later to retrieve edited values in the grid.

Also set initial values for cells to e.CellValues collection (dictionary<int, string>) - they will be used on the client side initially on first inline editing operation for each cell.

 

The result of using three small code blocks showed above is show on this picture:

image

Vertical scroll appeared for our GridView thanks to another extender I created earlier (Cross Browser GridView Fixed Header Extender, ASP.NET AJAX)

As you see You can simply click any cell and edit it's value - extender allows to do it without going to the server - all this functionality is done on the client.

Now when you do postback (for example user clicks "Save" button), you have access to all values that user have edited in "Values" property of extender.

This property is of type "Dictionary<string, Dictionary<string, string>>" - here outer dictionary's keys are row ids and inner dictionary's keys are cell indexes.

For example using this code we can handle / validate / and process all cell values edited by the user:

image

so for example let's edit two rows in the grid an click "Submit":

image

 

Extender has nice API on the client side as well. It allows to control the process of cells editing, and allows to simplify really complex scenarios.

Please review GridViewControlEmbedder.js file and especially functions inside "Public methods" region.

Extender has two client side events, to which you can subscribe to control/validate editing on the client side:

beforeCellEdit - occurs before cell is entered for edit.

afterCellEdit - occurs before cell is left and it's edited value is committed to the client-side state.

You can subscribe to these events in javascript using simple syntax:

image

where c.ce in string - ClientID of the extender.

Extender passes custom event args passed to the event handlers .

Constructors look like this:

image

 

As you can see you can cancel entering or exiting the cell by setting cancel property of event args. You can analyze the information about currently edited cell, row, column index, inner text of cell, also you have a reference to the grid from there. There is also "callBack" property that can be used to perform some asynchronous operation before continuing cell edit. For example you can set cancel property of event agrs to true to prevent continuing of current operation (entering/exiting cell), issue request to the server, and only after getting response you can call e.get_callBack() property - which is pointer to the function in the extender that will complete the operation.

I also created second demo page that shows how to use client side events of the extender to use inline editing with ComboBoxes. Here is the screenshot:

image

Demo page demonstrates using of drop down lists for choosing options for each cells. what options will be shown for what cell or row is pretty controllable from javascript code. Here is the code snippet from this demo page:

image

Here I call web service for options, passing it column index, then I set cancel property of event args to true to prevent entering the cell. After response is get back from the server, I grab the reference to the select element (e.get_control()) and fill it with options containing information got from the server. Finally I call callBack provided again in event args to enter cell and allow user to edit it.

 

Finally here is a full source code for the control and demo pages. Download and use it,

Hope this helps.

 

P.S.

I am thinking about moving all my control's source code - I write about in this blog, to the Codeplex project. This version of controls library also contains some fixed and upgraded controls from earlier blog posts - HoverTooltip, GridViewFixedHeaderExtender. I think I will move the source to the Codeplex about next week. Also I will update all old blog posts to link to Codeplex project for controls suite download.

kick it on DotNetKicks.com

Sunday, November 9, 2008

Code generation technique using MS codename "Oslo", T4 templating engine and VS Custom tool

You can download full source code for this post here.

Not long time ago Microsoft announced new product named "Oslo".

Quote from Microsoft Oslo Developer Center:

"Oslo" is the code name for our platform for model-driven applications. The goal of "Oslo" is to provide a 10x productivity gain by making model-driven applications mainstream with domain-specific models, a new language, and tools.

I will not go into much details about "Oslo" Modeling Platform, as I cannot define it better than "Oslo" SDK

I will quote one more definition from MS Developer Center, "Oslo" modeling platform contains the following parts:

  • A visual design tool (Microsoft code name “Quadrant”) that enables people to design business processes with well-understood, flowchart-like graphics; developers to design applications and components that comply with the requirements of those processes; and both to move from one view back and forth to observe the effect any changes in either place have on the overall validity of the application or business process. For more information, see "Quadrant".
  • A modeling language (Microsoft code name “M”) that makes it natural to extend system-provided models (such as Windows Communication Foundation (WCF) or Windows Workflow Foundation (WF) models) or create your own models for use on the “Oslo” modeling platform. For more information, see "M".
  • A SQL Server database (the code name “Oslo” repository) that stores models as SQL Server schema objects and model instance data as rows in the tables that implement the schema. This data is available to “Quadrant” and any other tool or data-driven application that can make use of it (and that has the appropriate permissions to do so). Whether models or model instance data is created visually, using “M”, or using any SQL data access API (for example, ADO.NET, EDM, OLE-DB, and so on) creating models and storing them in the “Oslo” repository enables future applications to examine and manipulate not only data structures used by applications but – because applications are modeled – the applications themselves, as they run. If data-driven application has enough detailed model information, applications can run without recourse to static compilation. For more information, see "Oslo" Repository.
  • However in the text above taken from "Oslo" overview there is no a single word about M Grammar - another cool part in "Oslo" product.

    Most of all I was exited with this modeling language MG (M Grammar). It can be used to create your own textual DSL-s (Domain Specific Languages), here is definition again from MSDN:

    The MGrammar Language (Mg) was created to enable information to be represented in a textual form that is tuned for both the problem domain and the target audience. The Mg language provides simple constructs for describing the shape of a textual language – that shape includes the input syntax as well as the structure and contents of the underlying information. To that end, Mg acts as both a schema language that can validate that textual input conforms to a given language as well as a transformation language that projects textual input into data structures that are amenable to further processing or storage. The data that results from Mg processing is compatible with Mg’s sister language, The "Oslo" Modeling Language, "M", which provides a SQL-compatible schema and query language that can be used to further process the underlying information.

    In this post I will try to shortly (but I am afraid in very technical details) introduce some cool sample I created on the weekend.

    1) I created my own domain specific language using M Grammar language from Oslo SDK,

    2) Created T4 Templating Engine Custom Host that will allow me to use T4 Templating Engine to generate code artifacts by parsing the "Data Graph" created by M Grammar language parser and

    3) Used Visual Studio Custom Tool to make possible the generation of multiply artifacts for single DSL file and placing them under that file in Visual Studio files hierarchy.

    The Domain Specific Language that I use in this sample is simple enough to make the sample easily understandable, but in real company - or product-wide DSL the language may be more complex. M Grammar gives the powerful options to create complex languages. You can find some samples of languages created using M Grammar under "%ProgramFiles%\Microsoft Oslo SDK 1.0\Samples\MGrammar\Languages".

     

    What this sample does ?

    The sample allows to use DSL language input files in Visual Studio C# applications. The files will contain code written on language that I wrote using M Grammar.

    Just create new VS project, add new file(s) inside it with ".dslcontract" extension:

    image

    Now write down some code using syntax of our custom language:

    image

    image

    Now lets save that files and see what we get:

    image

    Cool isn't it?

    As you see for each Enum construct custom tool have generated separate file with different extensions and language-specific contents:

    image

    image

    Now what is nice about the approach I used to create this functionality is - you can fully control

    1) for what type of language high level abstraction the code artifacts will be generated (Enum in this case, but language can hold Class or some another constructs in the future)

    2) for what Mg image file the code artifacts will be generated (I will define what is Mg image file later in the post)

    3) what types of code artifacts will be generated  (extensions, number of files for each high level abstraction, here by "high level abstraction" I mean syntax rule named "HighLevelAbstraction" in my custom DSL - you can see the listing of my language a little farther in the post),

    4) what will be the contents of generated code files (this is controllable through T4 templates and custom T4 text templating host I use in the sample)

    I will describe in more details each of the points above.

    1) (for what type of language high level abstraction the code artifacts will be generated )

    If you go to "%CommonProgramFiles%\Saatec.Dsl.Contracts.Language" path (this is where VS custom tool looks for resources, for use in production you can use different path for resources) you will see the following files:

    image

    Here by creating a new T4 templates (files with *.tt extension) and naming them with Enum.*.tt I can instruct the custom tool to generate one more artifact for each "high  level abstraction" in my language named "Enum". See also point No 4 below for description what will be used "*" part of the file name for.

    2) (for what Mg image file the code artifacts will be generated )

    On the picture above you may have already noticed file named "Saatec.Dsl.Contract.mgx". This file can be replaced at any moment with updated Mg image file  of my custom language(which optionally will support new constructs, rules and high level abstractions). Current simple language grammar in textual form looks like this:

    image

    You can find it's listing in Subfolder named "LanguageDevelopmentTools":

    image

    Here I placed

    a) shortcut for "Intellipad" - tool used to create textual DSLs using M Grammar,

    b) Saatec.Dsl.Contract.mg - M Grammar file containing Language definitions - syntax etc for our DSL,

    c) Test.dsl.contract - just test input file that can be used to see what output graph is generated for a language,

    d) PackLanguage.bat file - the batch file that compiles language (.mg) file into mgx image file and places it in one hierarchy above (for use by our VS  custom tool). I will place a screen-shot of "Intellipad" tool in action later in the post.

    3) (what types of code artifacts will be generated)

    I already mentioned that by creating Enum.*.tt file it is possible to instruct custom tool to use this T4 template to generate artifact for "high level abstraction" in my language named "Enum". By specifying extension instead of "*" sign we can give instruction to out VS custom tool to generate file of that extension. For example after finding file "Enum.cs.tt" in this folder, custom tool will generate file "Abstraction name".cs file (MessageBoxButtons.cs in our example).

    4) (what will be the contents of generated code files)

    Template files support text templating syntax, and after processing by templating engine will generate output for each single "high level abstraction" in my language. T4 templates can (and in most cases will) be host-specific,(host specific and are able to get reference to the hierarchical Data Graph produced by DSL language parser. See more information about "hostspecific" directive here.

    Typical T4 template looks like:

    image

    This template file name is Enum.cs.tt - it means it will be used to generate C# code file for each Enum "high level abstraction" in my domain specific language. Also you can see that I use GetOption method in the Host to get reference to a Data Graph, saying honestly I don't know what for GetOption should be used normally, I just noticed this method and that it is not called from inside templating engine, and I decided it is good method to override to provide a mechanism for passing my Data Graph to T4 templates. As you see graph is referenced at this line:

    image

    In the custom host implementation I overridden this method to return DSL parser output data graph:

    image

    where the mContractGraph is of type ContractGraph:

    image

    This graph gives a hierarchical view that describes what was in input DSL code file. Now we can use many of cool features of T4 to create artifacts. To make this possible I used Custom Text Template Host which ensures correct work of templates and provides reference to data graph. We will look at more details about it's implementation later (May be in next post?).

    Now what about error handling? - Currently the sample dumps all error texts into file under .dslcontract file that is named similarly as contract but has .txt extension. You should check this file after generation to be sure that process went smoothly. The file will accumulate errors raised by DSL language parser and T4 templating engine. The errors that are caused by custom tool itself can be viewed by clicking "Run Custom Tool" explicitly:

    image

     

    What can be used this sample for ?

    You can create simple DSL languages and generate multiply artifacts for input code files written using syntax of that languages.

    First of all DSL gives an opportunity to create simpler syntax than in languages you want generate code for.

    Secondly you can generate multiply code files on several languages for single DSL code file. This can give productivity boost in some situations, when a lot of "plumbing" code is needed, or when you have to generate similar structure code on several languages. For example in the sample I generate enumerations in C# and javascript code. This can be done easily by writing down 20-40 symbols and hitting "Save" opposed to several hundreds you had to write in common situation.

    And finally DSL is language agnostic - it does not depend on C# syntax and any other, it is parsed and data graph is produced that can be used to generate specific language code as well as XML, JSON, DB or any other structure.

     

    Implementation

    The architecture of the sample can be presented as follows:

    image

    Sorry for my designer skills :)

    Ok, so data flows the following way:

    1) User clicks "Save" or "Run Custom Tool" on original file in Visual studio.

    2) Custom tool gets reference to caller item, its text contents, default namespace etc. Custom tool calls "Code Generator" passing to it input text and default namespace

    3) Code generator calls DSL language Parser to populate data graph. It passes to it only original file's input.

    4) DSL Language Parser searches for language package on the disk in predefined location (configuration-driven approach can be added later), loads it, parses the input text and iterates trough all nodes in the graph, thus populating the internal - more user friendly data structure that will be later used in T4 templates.

    5) collection of graphs for each abstractions in input file are return back to "Code Generator" block.

    6) Code Generator block searches the predefined place on hard disk to find T4 template file for each graph. Graphs contain information about what kind of abstraction the represent. By using string name of an abstraction we can find actual template that will be used then.

    7) Code Generation block instantiates new Text Templating Engine in new AppDomain, and passes to it graph, template filename and custom host reference, starting with this text generation process.

    8) Text generation process is repeated for each graph and each template found for each graph type.

    9) Collection of generated code strings is passed back to custom tool, which in its turn uses Visual Studio automation to generate multiply files on the disk and subordinate them to original file in Visual Studio project.

    10) Finally Visual Studio will get generate files, and is ready to build.

    First of all to be able to run a sample code you have to download Oslo SDK from Microsoft website.

    It will install all tools and assemblies that are needed to author and parse textual DSLs, most specifically M Grammar.

    You can then quickly review "M Grammar in a Nutshell" document that will be available under Oslo program shortcut.

    It is really simple to get in quickly to M Grammar, You will have to use Intellipad tools to create your own language. It has good features - like syntax highlighting, error messages for syntax errors in M Grammar language code and more.

    The tool in action looks like this:

    image

    Here the language itself is in the center pane,

    Left pane will contain sample input for our language and

    Right pane will contain graph, that will be generated after parsing input.

    If there are any errors in input code you will see their details in the lower pane.

    There are more advanced ways of using complex languages - like using multiply files, you can see documentation, and very nice samples that come with Oslo SDK.

    After we created a language file, we can package it to file with .mgx extension, it can be later used by our applications to parse user input. What I really liked about M Grammar - it gives an opportunity of parsing input dynamically - this means  that languages can be used at runtime in our applications.

     

    So now we have our language file created and packed, lets see the VS solution for the sample.

    image

    Solution consists of four projects:

    CustomTool - The project containing class that implements IVsSingleFileGenerator interface - and implements it's methods "Generate" and "GetDefaultExtension". That class is called by VS when we hit "save" on file using that custom tool. Custom tool needs special registry keys to be set to point to its location. Also custom tool assembly should be registered with regasm tool, to be visible to VS COM process. I created "Install.bat" file that makes this actions automatically for you after each build of a solution. Also I created "Uninstall.bat" file which is also called each time before "Install.bat" is called. You can manually execute those files to uninstall or install our custom tool.

    Generator - this project implements all functionality that is used to parse our DSL language.  It should not be registered in GAC, because it references Oslo assemblies, that I could not register in GAC by some reason to the moment of writing this post.

    Interface - this is assembly that contains shared classes and interfaces needed for intercommunication of another assemblies in the solution. It should be registered in GAC. (This is done automatically by Install.bat" file I mentioned above.

    Generator.Host - this project implements custom text templating host. It is used to execute/ generate T4 templates and provide them graph for code generation. You can see it's implementation yourself, I really was not expecting that implementing custom host to be so simple. I just overrided several methods and properties to make it work in environment and AppDomain separated from Visual Studio.

     

    Some notes for getting started with the sample:

    After successful build of a solution please copy this directory:

    image

    To the path: %CommonProgramFiles%\Saatec.Dsl.Contracts.Language

    This is were custom tool will search for templates and language.

     

    Install.bat and Uninstall.bat files that are registering custom tool can be found here:

    image

    If you find this sample good for production you will have to create VS setup project and get rid of bat and reg files and instead use features of the project.

     

    To debug the custom tool just start another Visual Studio Instance and attach to it from VS running custom tool solution. Now after hitting "Save" on file with our custom tool in the VS instance being debugged you can hit breakpoints in our custom tool code.

     

    For generation of multiply files inside VS I use the code provided by Adam Langley (see below the original article URL).

    I think the post is going too long - so here is the source code. Download and use it on your own risk :)

     

    These two articles helped me a lot in understanding how T4 works under the hood, and how multiply files can be generated using T4 and VS Custom tool:

    How to generate multiple outputs from single T4 template

    Creating a Custom Tool to Generate Multiple Files in Visual Studio 2005

    Thanks to authors Oleg Sych and  Adam Langley for great articles and source code.

     

    Happy programming!

    kick it on DotNetKicks.com

    Monday, May 12, 2008

    Loading and Executing JavaScript Files From JavaScript, ASP.NET AJAX

    Download source code with samples for the article here.

    Quite often we need to load js files dynamically right from javascript. With ASP.NET AJAX it is simple.

    ASP.NET AJAX library has internal ScriptLoader class that can be used to load js files, specify callbacks that will be invoked when script is downloaded and ready, and execute functions inside newly loaded files.

    I will not list all available methods from ScriptLoader class - you can see them in more details in AJAX source.

    I will demonstrate how to load files and execute some functions in it.

    ScriptLoader has static and instance members. To add script references(urls) and script blocks to the loader we have to create instance of the class:

    image

    To add one or more script references to the loader use queueScriptReference method:

    image

    the parameter is path to the script file.

    And finally to load the file and insert link element to the body of the document use the following function:

    image

     

    Actually the loadScripts expects more parameters, but only first is required. The declaration of loadScripts function in AJAX library looks like this:

    image

    As you see the function can accept three callback functions that will be called when some condition is true: load was successful, load failed, or load was timed out.

     

    Whole sample will look like:

    image

    Test.js file contains the following code:

    image

    First line simply executes alert function.

    Second line is very important - this is how ScriptLoader knows when script is loaded to the end and calls success callBack.

    If you don't add this line to the end of the file ScriptLoader will never know is or is not script executed (loaded) to the end.

    Lets run the page:

     image

    Script was loaded and executed!

     

    Now lets try another example, where we will pass callback to the function to be able to call function inside dynamically loaded file, and be sure that it is loaded before we call anything in it.

    The page will look like:

    image

    and js file:

    image

    As you see we are calling the function inside file in callback, this way we ensure it is called AFTER file was loaded.

    Lets execute the page and first try to click second button:

    image

    Alert button says the script is not loaded yet - that's true. Now after we load the script (clicking on first button):

    image

    Is works.

     

    You may be wondering why you need this. But suppose you are loading contents to the browser dynamically, for example using web service or page method call, and the content is using javascript. You can also load dynamically it's script file and execute anything you need there.

     

    Hope this helps.

     

    Technorati Tags:

     

    kick it on DotNetKicks.com

    Using AjaxRepeater Control, ASP.NET AJAX

    You can download full source code with samples and controls for the article here.

    Recently after reading blog post Ajax Templates by Nikhil Kothari I really liked the idea, the source code is great, and the control is huge help for AJAX development.

    In this blog post I want to share what I learned after investigating sample more carefully, and in what scenarios I feel this control is doing it's job quite well.

    I want also to clarify that I will discuss this control's client side API, not touching it's server side capabilities.

    Also one thing to mention - I converted the source code from the sample to stand alone server control, and changed it's namespace to one used in my library. Please read carefully the header of the source for the control, it states the license and says you can freely use the source for commercial or not commercial software, there you can also find some limitations.

    Also - I modified only few lines of original code in the override of DataBind method, I wanted the template to be constructed even if I have no server side DataSource property specified.

    So what is AjaxRepeater control, and how to use it?

    To create Template, just drag the control on the page and specify template inside it, for example this way:

    image

    Here "itemTemplate" is the id of the element inside repeater. And inner XML/HTML of this element is the template representing one data item. In this case the template that will be repeated many times inside single "UL" element is:

    image

    "itemTemplate" id should be used for every template container, even if you have multiply AjaxRepeater controls on the page. Repeater finds template container to add template items to it by this id, searching for it inside parent AjaxRepeater control, which in the browser is rendered to DIV or SPAN element, depending on server-side property "RenderMode" which can be set to "Inline" or "Block". So this markup:

    image

    will be rendered in the browser (with empty data source) this way:

    image

    and this markup:

    image

    will be rendered as:

    image

     

    On the client side the repeater is javascript object, deriving from Sys.UI.Control, and it can be accessed using $find shortcut, specifying the ClientID of the control as control's ID. For example we can use this code to access the object:

    image

    The most important functions that we can call on the object are:

    set_data(value) - where value is the array of objects that is used to generate as many html items as are data items in the array. After calling this function, whole inner contents of item container will be cleaned and new items generated and added to the document under container element.

    addDataItem(dataItem) - adds one item to the container under last one. dataItem here is the object that will be used to generate one item from template.

    So we can use the following tricks:

    to clear the container:

    image

    to bind repeater to data source:

    image

    to incrementally add items to the container:

    image

    You may be interested what is generated in the html markup, let's see the result of execution of last sample:

    image

    And visually it looks like this:

    image

    Ok, lets see the simplest sample page that shows how to create items dynamically:

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Sample1.aspx.cs" Inherits="Sample1" %>
    <%@ Register Assembly="Devarchive.Net" Namespace="Devarchive.Net" TagPrefix="cc1" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <asp:ScriptManager runat="server" ID="SM">
        </asp:ScriptManager>
    
        <script type="text/javascript">
            function addItem(value) {
                var data = {text:value};
                $find("AjaxRepeater1").addDataItem(data);
            }
        </script>
    
        <div>
            <cc1:AjaxRepeater ID="AjaxRepeater1" runat="server" RenderMode="Block">
                <ul id="itemContainer">
                    <li>{text}</li>
                </ul>
            </cc1:AjaxRepeater>
            <input type="text" id="txt" />
            <input type="button" value="Add List Item" onclick="addItem($get('txt').value);" />
        </div>
        </form>
    </body>
    </html>
    

     

    As you see the code is really simple - when you enter some text in the text box and then click "Add List Item" button, new Item is generated and added to the container.

    The screen shot shows what we get:

    image

     

    Ok, lets look into templates, and data that is used to built the template. It is really simple. In the samples above

    Template:

    image

    is used to build item:

    image

    using this dataItem:

    image

    To build table rows for example,

    Repeater markup:

    image

    can be used to build the table with rows:

    image

    using this code:

    image

     

    Ok, but who said we cannot use repeater to generate only one item, and this way use it as client side view rather then repeater?

    This is simple, suppose we have the following view:

    image

    Here we can use the following code to rebind view with new data:

    image

     

    I want to say one more thing - js script for templating feature uses innerHTML to initially retrieve and parse the template in the browser, and this makes problems when we want to use templates inside style attributes of the elements.

    for example when using the following template, script cleans out the style attribute inner contents, when accessing it using innerHTML:

    image

    And renders it without styles, so to fix this I used a little fix/amend to the original script, With this approach you should use "_style" attribute instead of "style". Then when templating script loads the template it just strips out the leading underscore and generates correct items.

     

    Now ! I want to show you the scenario which is really easy to achieve with this control !

    Suppose you want to bind data from the web service. For example you want to fetch data and bind it to the view or repeater. It is simple!

    As we know web services (and page methods) have nice built in feature - when called from javascript they are serializing return objects into JSON - and therefore can be used to fetch data and set it to the repeater right from the browser.

    The source code for the sample page demonstrating this is:

     

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Untitled Page</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <asp:ScriptManager runat="server" ID="SM">
            <Services>
                <asp:ServiceReference Path="~/WebService.asmx" />
            </Services>
        </asp:ScriptManager>
        <script type="text/javascript">
            function bind() {
                WebService.GetData(function(result) {
                    var rpt1 = $find("rpt1");
                    rpt1.set_data(result);
                });            
            }
        </script>
        <div>
            <input type="button" onclick="bind();" value="Bind From Service" />
            <dn:AjaxRepeater runat="server" ID="rpt1">
            <table cellpadding="4" cellspacing="2" width="400px">
                <tbody id="itemContainer">
                    <tr>
                        <td _style="{style1}">{field1}</td>
                        <td _style="{style2}">{field2}</td>
                        <td _style="{style3}">{field3}</td>
                        <td _style="{style4}">{field4}</td>
                    </tr>
                </tbody>
            </table>
            </dn:AjaxRepeater>
        </div>
        </form>
    </body>
    </html>
    

     

    WebService.cs :

     

    using System;
    using System.Collections;
    using System.Web;
    using System.Web.Services;
    using System.Web.Services.Protocols;
    using System.Collections.Generic;
    using System.Web.Script.Services;
    
    [WebService]
    [ScriptService]
    public class WebService : System.Web.Services.WebService
    {
        Random r = new Random();
    
        [WebMethod]
        [ScriptMethod]
        public List<Data> GetData()
        {
            List<Data> data = new List<Data>();
            for (int i = 0; i < 5; i++)
            {
                Data d = new Data();
                d.field1 = "field1_" + i.ToString();
                d.field2 = "field2_" + i.ToString();
                d.field3 = "field3_" + i.ToString();
                d.field4 = "field4_" + i.ToString();
                d.style1 = "background-color:" + getRandomColor();
                d.style2 = "background-color:" + getRandomColor();
                d.style3 = "background-color:" + getRandomColor();
                d.style4 = "background-color:" + getRandomColor();
                data.Add(d);
            }
            return data;
        }
    
        private string getRandomColor()
        {
            string result = "#";
            for (int i = 0; i < 6; i++)
            {
                result += r.Next(0, 10).ToString();
            }
            return result;
        }
    
        public class Data
        {
            public string field1;
            public string field2;
            public string field3;
            public string field4;
            public string style1;
            public string style2;
            public string style3;
            public string style4;
        }
    }
    Is not this simple?
    Here is the result page's screen shot:
     

    image

     

    Guys, we can use the control to build really cool dynamic contents using templates and web services !

     

    Ok, but what about performance ? -

    As I measured - on my computer (Athlon 64 4800+, 2 GB RAM DDR2) to fetch and build 5000 items in the repeater with markup used above it took only 13 seconds, this means 13/5000 = 0.0026 seconds for one template. Taking into account that performance degrade gracefully with growth of html markup size, these are really good figures. Besides this some time is spent to generate response on the server, and deserialize it on the client, all this is done in 13 seconds.

     

    Now suppose scenarios when we have a lot of repeaters and views on the page - only templates are loaded first time, and all the data is bound later. This is really good approach very often - we can bind whole grids with sorting/paging this way, just need to specify sort direction and page number when calling web service. Or we can use master-detail relationship - where we select row in the table (master) which was bound using service, and in click event of the row bind view with corresponding data from service (details).

     

    I hope this article will help you start with the control, And want to thank Nikhil for the great work.

     

    Technorati Tags:

     

    kick it on DotNetKicks.com