Creating your first mixed client/server control

Calipso's mixed client/server controls have two parts:

- A server-side Comkarl.Web.UI.ScriptControl .NET derived class.
- A client-side Comkarl.Web.UI.Control JavaScript derived class.

1. Understanding and developing the server-side part

Server-side part of a control is just like any other plain ASP.NET Web Forms server control (don't confuse this with User Controls (ASCX), Calipso won't never support them).

Comkarl.Web.UI.ScriptControl class is the base one for any server-side control that should work together with a JavaScript, client-side counterpart.

Any derived class must override the following properties:
  • CommonID. It's the control identifier that will identify your control in the server and client side. It's mandatory because it's the approach to communicate each tiers. It's a text identifier like a variable name.
  • ControlElementCssClass. It's the control container CSS class name. It's mandatory because it's required for locating your control in the client-side document object model (DOM). For example, using jQuery $(".YourControlClassName").

Once you've derived your class from the appropiate base one, next step is creating the JavaScript file that will represent your control in the client side.

The recommended project structure (it's not mandatory) is creating a directory in your Visual Studio project with the name of your control, and JavaScript file should be called "ScriptControl.js". ScriptControl.js must be an embedded resource. Go to Visual Studio file Properties panel and change "Build Action" to "Embedded Resource".

Now that you've the JavaScript file created, go back to your ScriptControl-derived class and override the OnLoad virtual method. In order to tell to Calipso that using your server control requires a JavaScript file in the client-side is registering an include and a reference to it in the JavaScriptManager.

Check the next picture: 2.png

Override OnLoad method this way:
protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            JavaScriptManager.RegisterInclude
            (
                "Classes//UI/Controls/SampleControl",
                "Comkarl.Web.SampleClient.Controls.SampleControl.ScriptControl.js, Comkarl.Calipso.Web.SampleClient",
                JavaScriptIncludeKind.Resource
            );

            JavaScriptManager.RegisterReference("Classes//UI/Controls/SampleControl");
        }

  • RegisterInclude(...) statement tells JavaScriptManager that:
    • ...it must register an include called "Classes//UI/Controls/SampleControl"
    • ...the include is a JavaScript file located in "Comkarl.Calipso.Web.SampleClient.Controls.SampleControl.ScriptControl.js, Comkarl.Calipso.Web.SampleClient".
    • ...the include is an embedded resource.
  • RegisterReference(...) statement tells JavaScriptManager that an include called "Classes//UI/Controls/SampleControl" must be loaded in the client-side of current Web page.

Finally, you must register your control in some master page or content page like any other regular server control. For example, your control's full name is "Samples.Controls.MyControl" and it's in an assembly called "Samples.Web", registration would be made this way:
<%@ Register TagPrefix="Samples" Namespace="Samples.Controls" Assembly="Samples.Web" %>


... and you would add your server tag to your master page or content page:
<Samples:MyControl ID="blah" ParentElementSelector="body" runat="server" />

Why ParentElementSelector?

Think that this kind of control can send (X)HTML from the server side or maybe it renders everything in
the client-side using jQuery or any other library. ParentElementSelector specifies a CSS selector to the parent element where your control will be nested in your Web page.

2. Understanding and developing the client-side part

Usually, client-side part is just the embedded JavaScript file of previous point (1).

This JavaScript file:
  • Declares a JavaScript class that derives Comkarl.Calipso.Web.UI.Controls.Control.
  • It registers the class into the client-side PageManager (this is mandatory in order to initialize and render your client-side control).

A client-side JavaScript control looks like this:
$namespace.register("Comkarl.Calipso.Controls");

Comkarl.Calipso.Controls.SampleControl = $class.declare(
    function () { },
    {
        Initialize: function () {
        },

        Render: function () {
        }
    },
    Comkarl.Web.UI.Controls.Control
);

Comkarl.Web.PageContext.get_Manager().RegisterControl("SampleControl", Comkarl.Calipso.Controls.SampleControl);


Some summary and explanations of above code:
  • Since JavaScript isn't a compiled code, it's mandatory that controls registers its namespace, because if any other one in the page doesn't register the whole namespace, your control won't load because a null reference error in the client-side.
  • Any client-side control has two overridden functions:
    • Render. It's the first function called when PageManager loads the control. It's the place where you can place rendering code, like creating a paragraph, DIV or any other.
    • Initialize. It's called just after Render. This function will be the right place to bind event handlers, prepare some data and set to some HTML element...

Actually you can place code in both functions and do anything there, but those have been designed to place things in a logical order ;)

Pay special attention to this line:
Comkarl.Web.PageContext.get_Manager().RegisterControl("SampleControl", Comkarl.Calipso.Controls.SampleControl);

"SampleControl", the first argument given to RegisterControl(...) function must be the CommonID that you specified in the server-side!.

This is the most simple form of a client-side control. In order to print a "Hello world" text you could add this code to the Render(...) function:

        Render: function () {
                  var lblHelloWorld = $("<span />");
                  lblHelloWorld.text("Hello world!");
                  
                  $(this.get_ParentElementSelector()).append(lblHelloWorld);
        }


Last edited Aug 14, 2012 at 2:10 PM by MFidemraizer, version 22

Comments

No comments yet.