Blog Moved ....



my book(s)

my products

Part 2 of 2 : Delegates/Inheritance in .NET and MS Ajax

In Part 1 of this series, I showed how delegates work in C#. We created a matrix that was populated with a delegated function call. This function was responsible for performing the display result in each cell of the matrix.

In today's post, we wish to accomplish the same results, but instead of using C#, we're going to be using JavaScript against the Microsoft ASP.NET Ajax Extensions. Currently we're building on Beta 2 of these extensions.

First, let's have a look at the code behind(side) C# file.

   1:  using System;
   2:  using System.Web.UI;
   4:  public partial class ClientSideDelegate : Page
   5:  {
   6:      protected void Page_Load ( object sender, EventArgs e )
   7:      {}
   8:  }

Nothing. There is not an ounce of C# code running this sample, in fact, we don't even need a code behind(side) file.

Here are screen shots of the finished product running, to give you a good mental picture of what we want to accomplish.

No Math, Just display X,Y Matrix
No Math Function, Just Display X, Y

The Addition Matrix
The Add Matrix

Subtract Matrix
The Subtract Matrix

Multipy Matrix
The Multiply Matrix

Remember our goal. Create the matrix with a single set of code, that is reused over and over again, for every math function.

One thing you'll notice is that I've changed the title of part 2, to be delegates/inheritance. This is because after looking at the JavaScript code (you'll see this in a moment) that it looks/acts more like inheritance then it does a delegate. Although it kind of looks the same, we actually pass in a class that matches our signature. You'll see as we go through the article.

OK, here is the ASP.NET code.

   1:  <asp:ScriptManager ID="ClientMatrixScriptManager" runat="server">
   2:      <Scripts>
   3:          <asp:ScriptReference Path="ClientSideDelegate.aspx.js" />
   4:      </Scripts>                
   5:  </asp:ScriptManager>
   7:  <asp:DropDownList ID="OperationList" runat="server" OnChange="DrawMatrix(this.value)" >
   8:      <asp:ListItem Selected="True" Text="Do...." Value="0" />
   9:      <asp:ListItem Text="No Math" Value="0" />
  10:      <asp:ListItem Text="Add" Value="1" />
  11:      <asp:ListItem Text="Subtract" Value="2" />
  12:      <asp:ListItem Text="Multiply" Value="3" />
  13:  </asp:DropDownList>
  15:  <div id="Matrix">
  16:  </div>

Nothing tricky, just a drop down list with some options, and an empty div tag that we'll fill with our Client Side Matrix. Also notice that on line 3 is where we're setting up the reference to our external JavaScript file. We do this inside the script manager so the external file is sure to be loaded after all the other MS Ajax scripts have been loaded. Also notice that the OnChange client event of the DropDownList is set to call a function called "DrawMatrix()" that takes the value of the drop down list as a parameter. This will be the integer value of 0-3, and again (as you'll see) we'll create an Enumerator in JavaScript to work the same as it did in C#.

What the MS Ajax Extensions give us is pseodu .NET in JavaScript. The first thing that we need to do is create/register a namespace. This does some wiring under the hood that will later let us register classes, enums, and other stuff to that namespace.

   1:  //register name space
   2:  registerNamespace('ScottCate');

You might be asking -- "What does the registerNamespace() method call into?" And that's a great question. It calls in the Core MS Ajax Extension libraries that are loaded from the script manager. For now, we'll just call it automagic.

Remember the Enumertor I was talking about using? Here it is defined in JavaScript.

   1:  //setup enum
   2:  ScottCate.MathOperator = function() {
   3:  }
   4:  ScottCate.MathOperator.prototype = {
   5:    None: 0,
   6:    Add: 1,
   7:    Subtract: 2,
   8:    Multiply: 3
   9:  }
  10:  // the second param determines if the Enum is flagged
  11:  ScottCate.MathOperator.registerEnum("ScottCate.MathOperator", false);

Line 11 calls a registerEnum method and registers the MathOperator Enumerator. Now we have an Enum (like) class in JavaScript that is going to act just like we would expect it to, knowing everything we already know about Enums in .NET including flagging (second parameter); 

Next, is the MatrixWorker JavaSript Method() inside of DelegateSample.aspx.js. This is going to be our work horse that does the actual Martix building for us.

   1:  function MatrixWorker(mathDelegate) {
   2:      var matrix = $get('Matrix');
   3:      var matrixString = new Sys.StringBuilder('<table border=1>');
   4:      for(x = 0; x <= 10; x++) {
   5:          matrixString.append('<tr>');
   6:          for(y = 0; y <= 10; y++) {
   7:              matrixString.append('<td>');
   8:              var math = new mathDelegate(x,y);
   9:              matrixString.append( math.toString() );
  10:              matrixString.append('</td>');
  11:          }
  12:          matrixString.append('</tr>');
  13:      }
  14:      matrixString.append('</table>');
  15:      matrix.innerHTML = matrixString.toString();
  16:  }

Notice on line 8 where we "New" up an instance of the class that is passed in. These classes will be part of an inheritance chain that will know how to give back the appropriate string presentation for the Math function they're responsible for. We simply nest this call inside two fro loops that will create our table, rows, and cells. When it's done (on line 15) we simply stuff the contents inside the div tag.

Next we need to create our Math classes that will be used to create our cell results. We'll start just generating the classes. On lines 1-20 we create our base math class. Then on lines 21-27 we create our first child of Math called AddMath. Line 23 calls an initializeBase method, and passes off the X,Y values to it's parent. Then we repeat the options for Subtract and Multiply. See how we're creating an individual toString() method for each class?

   1:  //setup base method
   2:  ScottCate.Math = function(a,b) {
   3:      this._a = a; //value of a or 0
   4:      this._b = b; //value of b or 0
   5:  }
   6:  ScottCate.Math.prototype = {
   7:      get_a: function() {
   8:          return this._a;
   9:      },    
  10:      get_b: function () {
  11:          return this._b;
  12:      },
  13:      toString: function() {
  14:          return this.get_a() + ',' + this.get_b();
  15:      },
  16:      dispose: function() {
  17:          //gone;
  18:      }
  19:  }
  21:  //setup add function
  22:  ScottCate.AddMath = function(a,b) {
  23:      ScottCate.AddMath.initializeBase(this, [a,b]);
  24:  }
  25:  ScottCate.AddMath.prototype.toString = function() {
  26:      return this.get_a() + this.get_b();
  27:  }
  29:  //setup subtract function
  30:  ScottCate.SubtractMath = function(a,b) {
  31:      ScottCate.SubtractMath.initializeBase(this, [a,b]);
  32:  }
  33:  ScottCate.SubtractMath.prototype.toString = function() {
  34:      return this.get_a() - this.get_b();
  35:  }
  37:  //setup multiply function
  38:  ScottCate.MultiplyMath = function(a,b) {
  39:      ScottCate.MultiplyMath.initializeBase(this, [a,b]);
  40:  }
  41:  ScottCate.MultiplyMath.prototype.toString = function() {
  42:      return this.get_a() * this.get_b();
  43:  }

And then registering the classes with the MS Ajax Extensions.

   1:  //register classes
   2:  ScottCate.Math.registerClass('ScottCate.Math',  null, Sys.IDisposable);
   3:  ScottCate.AddMath.registerClass('ScottCate.AddMath', ScottCate.Math);
   4:  ScottCate.SubtractMath.registerClass('ScottCate.SubtractMath', ScottCate.Math);
   5:  ScottCate.MultiplyMath.registerClass('ScottCate.MultiplyMath', ScottCate.Math);

Notice the registration of each class is done so be defining it's parent for inheritance. the Math class doesn't have a parent, but it does implement IDisposable. Yes Interfaces are supported to :). Then AddMath, SubtractMath, and MultiplyMath all inherit from Math.

Finally, the missing piece is the DrawMatrix() method that is called from the Client Drop Down List. A nice little JavaScript switch statement using our Enumerator to decide which class to use to call into the Matrix Worker.

   1:  function DrawMatrix(operator) {
   2:      //make sure operator is a number
   3:      switch(parseInt(operator)) {
   4:          case ScottCate.MathOperator.None:
   5:              MatrixWorker(ScottCate.Math);
   6:              break;
   7:          case ScottCate.MathOperator.Add:
   8:              MatrixWorker(ScottCate.AddMath);
   9:              break;
  10:          case ScottCate.MathOperator.Subtract:
  11:              MatrixWorker(ScottCate.SubtractMath);
  12:              break;
  13:          case ScottCate.MathOperator.Multiply:
  14:              MatrixWorker(ScottCate.MultiplyMath);
  15:              break;
  16:      }
  17:  }

And Pooof. You have just experienced Inheritance/Delegate like behavior in JavaScript running against the Microsoft ASP.NET Ajax Extensions.



No Comments