导航

Today I decided to set myself a little challenge, I wanted to see if I could use the Control Adapter framework which shipped with ASP.NET 2.0 that allows the developer to override and uniquely control the rendering of all the ASP.NET controls, to render and ASP.NET page in normal HTML for IE and in XAML for Firefox.

 

This little project took me three hours to put together and get to the stage where I can write about my experience, so it’s a bit rough and ready!

 

SOURCE CODE CAN BE FOUND HERE

http://www.myservicescentral.com/CodeSamples/CssAdapters1.zip

 

A little background before we move on, I’ve not really used XAML yet, but understand it will be the markup for future Windows Forms style applications and will force all those Windows Developer to learn how to use <spikey brackets />. A friend of mine has been ranting on for years about how ASP.NET will be the platform of the future and how it will render out content as it see’s fit, with that in mind, I thought I’d take a stab at producing XAML from ASP.NET controls.

 

The first thing I did was checked out this post from Scott Guthrie on the ASP.NET 2.0 Control Adapter Architecture. Then I grabbed a copy of the CSS Adapter Toolkit, which details how to create CSS friendly controls and gives some really cool examples of some of the ASP.NET controls which have already been CSSified (is that a word? Well it is now!).

 

After reading through the source code which is all provided with the CSS Adapter Toolkit I was SCARED at how EASY it all was!

 

The fist thing I did was create a page which I could use to test my XAML Adapters.

 

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="XamlPage.aspx.cs" Inherits="XamlPage" %>

<form runat="server">

 <p>Here is some content</p>

 <asp:Label id="EmailLabel" runat="server" Text="What is your e-mail address?"></asp:Label>

<asp:TextBox id="EmailTextBox" runat="server" Text="Type your e-mail address here." />

<asp:RequiredFieldValidator id="EmailRequired" runat="server" ControlToValidate="EmailTextBox" ErrorMessage="Email Address is Required" />

 <asp:Button id="EmailButton" runat="server" Text="Register your e-mail address!" />

 </form>

 

Once I had my page it was time to build my first Adapter so I set to it at the top level and decided to create my own System.Web.UI.Page implementation which instead of squirting out something like <html><head /><body></body></html> needed to produce the XAML equivalent which is <application></application>. The code was amazingly simple: -

 

using System;

using System.Web;

using System.Web.UI;

 

namespace Plipster.XamlAdapters

{

    public class PageXamlAdapter : System.Web.UI.Adapters.PageAdapter

    {

        protected override void Render(HtmlTextWriter writer)

        {

 

            writer.WriteLine();

            writer.WriteBeginTag("Application");

            writer.Write(">");

            writer.WriteLine();

 

            base.Render(writer);

 

            writer.WriteLine();

            writer.WriteEndTag("Application");

 

        }

 

        public PageXamlAdapter()

        {

        }

    }

}

Once the control had been created I needed to tell ASP.NET to use my new control in place of the standard System.Web.UI.Page control under the circumstances that I wanted it to. In the Real World those circumstances would be “The client is running WinFX and can support XAML”, in the world of test environments it was “The client is running Firefox so we’ll pretend that’s WinFX”.

 I created this browser file: -

 <browsers>

 <browser refID="MozillaFirefox">

    <controlAdapters>

      <adapter controlType="System.Web.UI.Page"             adapterType="Plipster.XamlAdapters.PageXamlAdapter" />

    </controlAdapters>

 </browser>

</browsers>

 

So once this is all set up, requesting any ASP.NET page through firefox just returns the following content: -

 <Application></Application>

 

Extend it a little bit and create all the Controls that I listed in the page with their XAML equivalents and you get something like this: -

 

<Application>

<Canvas Background="LightCyan">
<Text>
<p>Here is some content</p>
</Text>
<Text>What is your e-mail address?</Text>
<TextBox>Type your e-mail address here.</TextBox>
<Text Color="Red">Email Address is Required</Text>
<Button>Register your e-mail address!</Button>
</Canvas>
</Application>

 

 

So what’s so cool about this? Well it shows the true power of control adapters, it also shows how easy they are to manipulate and bend to your own will.

 

Next steps: -

 

  1. How do you get code (C#/VB.NET) to work with this XAML?
    1. Do we go about rendering and compiling on the server and then stream down a binary with all the code pulled together on the server and compiled?
    2. Perhaps some form of Ajax style abstraction layer such as Atlas will communicate from the client to the server – maybe even use Atlas and XMLScript to do this?
  2. What else can we produce, not just XAML and HTML, surely there are other markups or text based languages we can produce with the adapters.
    1. What about a Java Adapter, one which produces client runnable applications that can be created to run on non Windows Machines?
    2. Mobile devices – what a huge topic, and exercise for the reader I think!
    3. How cool would a Windows Forms Adapter be – how about a bit of code generation, server side compilation and then binary stream of an executable down to a client – it’s just text after all! Here’s the Windows Forms code for a similar UI to the one ASP.NET produced.

 

private void InitializeComponent()

{

      this.label1 = new System.Windows.Forms.Label();

      this.EmailLabel = new System.Windows.Forms.Label();

      this.EmailTextBox = new System.Windows.Forms.TextBox();

      this.EmailButton = new System.Windows.Forms.Button();

      this.SuspendLayout();

      //

      // label1

      //

      this.label1.Location = new System.Drawing.Point(16, 40);

      this.label1.Name = "label1";

      this.label1.Size = new System.Drawing.Size(120, 23);

      this.label1.TabIndex = 0;

      this.label1.Text = "Here is some content";

      //

      // EmailLabel

      //

      this.EmailLabel.Location = new System.Drawing.Point(24, 96);

      this.EmailLabel.Name = "EmailLabel";

      this.EmailLabel.Size = new System.Drawing.Size(160, 23);

      this.EmailLabel.TabIndex = 1;

      this.EmailLabel.Text = "What is your e-mail address?";

      //

      // EmailTextBox

      //

      this.EmailTextBox.Location = new System.Drawing.Point(208, 96);

      this.EmailTextBox.Name = "EmailTextBox";

      this.EmailTextBox.Size = new System.Drawing.Size(136, 20);

      this.EmailTextBox.TabIndex = 2;

      this.EmailTextBox.Text = "Type your e-mail address";

      //

      // EmailButton

      //

      this.EmailButton.Location = new System.Drawing.Point(24, 144);

      this.EmailButton.Name = "EmailButton";

      this.EmailButton.Size = new System.Drawing.Size(176, 23);

      this.EmailButton.TabIndex = 3;

      this.EmailButton.Text = "Register Your e-mail address";

      //

      // Form1

      //

      this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

      this.ClientSize = new System.Drawing.Size(400, 238);

      this.Controls.AddRange(new System.Windows.Forms.Control[] {

                                                                                                      this.EmailButton,

                                                                                                      this.EmailTextBox,

                                                                                                      this.EmailLabel,

                                                                                                      this.label1});

      this.Name = "Form1";

      this.Text = "Form1";

      this.ResumeLayout(false);

 

}

 

 

Okay I think that’s enough food for thought – play nicely now children J