Blog Home  Home Feed your aggregator (RSS 2.0)  
Microsoft AJAX Library (Atlas) – Javascript OOP enhancements (Part 2) - Manuel Abadia's ASP.NET stuff
 
# Wednesday, 11 October 2006

Note: Bertrand Le Roy has confirmed that the next Microsoft AJAX Library release will use the prototype based approach instead of the closure approach (really great news!), and clearly explains the differences:

http://weblogs.asp.net/bleroy/archive/2006/10/11/From-closures-to-prototypes_2C00_-part-1.aspx

In part 1 we saw how the inheritance infrastructure worked, how to create namespaces, and how to create classes. Now it is time to continue with the other stuff.

Interfaces

To create an interface is similar to create a class, but we use the registerInterface method instead and we define the methods to be abstract. For example:

Manu.Atlas.Tests.MyInterface = function() {

   this.method1 = Function.abstractMethod;

}

 

Manu.Atlas.Tests.MyInterface.registerInterface('Manu.Atlas.Tests.MyInterface');

We can define the interface using the prototype method instead of the closure method:

Manu.Atlas.Tests.MyInterface = function() {

}

 

Manu.Atlas.Tests.MyInterface.prototype.method1 = Function.abstractMethod;

 

Manu.Atlas.Tests.MyInterface.registerInterface('Manu.Atlas.Tests.MyInterface');

 

The registerInterface method (defined in the Function type) just set the _typeName of the type where the method is invoked, and sets the boolean properties _interface, _abstract and _sealed to true.

Enumerations

There are two kinds of enumerations that we can create. One where the enumeration items act as flags so we may want to combine them and the other type is where we can’t combine the enumeration items.

The first type is created using the createFlags method and the second one is created using the createEnum method (of the Type class). The parameters for those methods are:

Type.createFlags(enumerationName, enumerationItems)
Type.createEnum(enumerationName, enumerationItems)


Where enumerationName is the name of the enumeration, and enumerationItems are a variable number of parameters that specify the different enumeration items. Each item in the enumeration is specified as two parameters, the first is the string with the item name, and the second the associated value.

The common methods are:
• toString: converts the value passed to the method to a string.
• parse: converts the string passed to a value.
• getName: returns the name of the enumeration

The enumeration where you can use the items as flags has a method called isFlags that return true. The other enumeration type has a method called isEnum that returns true, and a method called getValues that returns a hashtable with the items of the enumeration.

An example follows:

Type.createEnum('Manu.Atlas.Tests.MyEnum', 'enum_item1', 1, 'enum_item2', 2);

var val = Manu.Atlas.Tests.MyEnum.enum_item1;

var str = Manu.Atlas.Tests.MyEnum.toString(val);

var valaux = Manu.Atlas.Tests.MyEnum.parse('enum_item2');

 

Type.createFlags('Manu.Atlas.Tests.MyEnum2', 'enum_item1', 1, 'enum_item2', 2, 'enum_item3', 4);

var val2 = Manu.Atlas.Tests.MyEnum2.enum_item1 | Manu.Atlas.Tests.MyEnum2.enum_item3;

var str2 = Manu.Atlas.Tests.MyEnum2.toString(val2);

var val2aux = Manu.Atlas.Tests.MyEnum2.parse('enum_item2 | enum_item3');

The values of the variables after execution are:

val = 1
str = “enum_item1”
valaux = 2
val2 = 5
str2 = “enum_item1 | enum_item3”
val2aux = 6

Both kinds of enumerations are implemented the same way. A hashtable with the same name as the enumeration is created, and each enumeration item name is stored as a key of the hashtable and the enumeration item value is stored as the associated value for the key.

From now on, when showing a class or an interface, I’ll be using C# syntax to show it instead of the JavaScript version of the class for clarity. The naming convention for the JavaScript classes is distinct from the C# naming convention so if a property is called Text in C#, the equivalent getter and setter will be get_text and set_text instead of get_Text and set_Text, so don’t get confused.

Attributes

In .NET is very common to decorate classes, properties and methods with attributes that provide useful information about them. The Microsoft AJAX library adds this extension to JavaScript.

The attributes are very important to generate reusable code. The xml-script parsing process and the validation controls use it.

An attribute is a static property of the class Sys.Attributes. The class has a method called defineAttribute that creates a new attribute:

Sys.Attributes.defineAttribute('MyCustomAttribute');

After having created the attribute we can reference it using Sys.Attributes. 'MyCustomAttribute. The attributes can be associated to a class or to a property as we will see in the next section.

Reflection

Even if JavaScript has some flexibility that can be used to perform some tasks similar to what reflection does (retrieve all fields from an object, retrieve a field from an instance using a string with the property name, invoke a method from an object based on the method name, etc), as the Microsoft AJAX library added OO features to it, it has to provide a way to interact with all the new OO infrastructure generically and more .NET friendly.

These features are provided by the Sys.TypeDescriptor class. Most of the classes in the library implement the interface ITypeDescriptorProvider:

public interface ITypeDescriptorProvider

{

    TypeDescriptor GetDescriptor();

}

The only method present in the interface returns the TypeDescriptor for the class implementing the interface.

The TypeDescriptor class is like this:

public sealed class TypeDescriptor

{

    public void AddAttribute(string name, object value);

    public void AddEvent(string name, object supportActions);

    public void AddMethod(string name, object value);

    public void AddProperty(string name, Type type, bool readOnly, params object[] attributes);

 

    public TypeDescriptor();

 

    public static void AddType(string tagPrefix, string tagName, Type type);

    public static Type GetPropertyType(object instance, string name, string key);

    public static Type GetType(string tagPrefix, string tagName);

    public static TypeDescriptor GetTypeDescriptor(object instance);

 

    public static object InvokeMethod(object instance, string name, object[] parameters);

    public static ParameterInfo CreateParameter(string name, Type type);

    public static string GetAttribute(object instance, string name);

    public static object GetProperty(object instance, string name, string key);

    public static void SetProperty(object instance, string name, object value, string key);

 

    public static void Unload();

}

A class implementing ITypeDescriptorProvider returns a new instance of the TypeDescriptor class where all the attributes, properties, methods are events supported by the class have been added using the AddXXX instance methods. The CreateParameter method is used with the AddMethod method to specify the parameters for the method.

The information about a particular instance is stored in four dictionaries (_attributes, _events, _methods and _properties). The static methods AddType and GetType are used to register types and to get information about the registered types in the system. The TypeDescriptor class has a static field called _registeredTags (of type hashtable), where it stores a hashtable of typeNames and its associated type, using the tagPrefix as key. This is mainly used by the xml-script infrastructure as we’ll see in a future post. The Unload method erases the information stored in the _registeredTags hashtable.

The other methods are self explanatory.

Events

The event mechanism implemented by the library is very reminiscent of the .NET one, although it has some differences.

An event is an instance of the Type.Event class:

public sealed class Event : IDisposable

{

    public bool AutoInvoke { get; }

    public bool IsInvoked { get; }

 

    public Event(Component owner, bool autoInvoke);

 

    public void Add(JavascriptFunction handler);

    public void AddAction(IAction action);

    public void Remove(JavascriptFunction handler);

    public void RemoveAction(IAction action);

 

    public bool IsActive();

    public void Invoke(object sender, EventArgs eventArgs);

    public void SetInvoked(bool invoked);

 

    public void Dispose();

}

An event is declared like this:

this.propertyChanged = new Type.Event(null, false);

And to subscribe to the event we have to write the following code:

var propertyChangedHandler = Function.createDelegate(this, onPropertyChanged);

myInstance.propertyChanged.add(propertyChangedHandler);

the onPropertyChange method will be called when the event is fired. The method should have a signature like this:

function onPropertyChanged(sender, args) {

}

And the first parameter will be the object that fired the event, and the second parameter will be the arguments specific for the event.

The arguments are an instance of the class EventArgs or any of its subclasses:

public class EventArgs : ITypeDescriptorProvider

{

    public static EventArgs Empty = new EventArgs();

 

    public EventArgs();

 

    public virtual TypeDescriptor GetDescriptor();

}

Note that the EventArgs class implements the ITypeDescriptorProvider interface explained before.

The Event class implements the IDisposable interface that is like this:

public interface IDisposable

{

    void Dispose();

}

 

yes, the same as .NET.

The Event class has methods to add and remove event handlers and also to add and remove actions. What is an action? Actions will be covered in more detail in a future post but for now think of them as tasks that can be executed before the event handler is called or after the event handler is called.

The Event constructor takes a Component as the first parameter, because actions operate on components. The autoInvoke parameter is used to call to a handler when adding it to the event if the event has already been fired. This is useful because some critical methods should be called in response to events that may happen before the full Microsoft AJAX Library has been initialized.

Additions to the default JavaScript objects

The library adds some methods to the default JavaScript objects to make them more .NET alike:

Boolean -> parse
Number -> parse
String -> startsWith, endsWith, lTrim, rTrim, format, localeFormat
Array -> add, addRange, cloar, clone, contains, dequeue, indexOf, foreach, insert, remove, removeAt, parse, get_length, get_Item. Also, Array implements the IArray interface (get_length, get_Item).

RegExp -> parse

Error -> createError (that is the replacement for: throw new Exception(…) in the .net framework.

Date -> toFormattedString, serialize

In the next post I’ll talk about the Component class and related classes. There is a lot of theory behind it to fully understand all the details involved…

Wednesday, 11 October 2006 10:22:24 (Romance Daylight Time, UTC+02:00)  #    Comments [5]   Ajax | ASP.NET | JavaScript  | 
Copyright © 2018 Manuel Abadia. All rights reserved.
DasBlog 'Portal' theme by Johnny Hughes.