Freigeben über


VB4: "XAML, I am your father"

I think I've mentioned before that I've been a Visual Basic developer since the glory days of VB 1.0. While these days I prefer the syntax of C#, I still dabble in VB fairly often (usually because I've been the only one in p&p who will write VB QuickStarts!), and I often think that the contributions that VB has made to software development as a whole are often underrated. While its popularisation of concepts such as GUI designers, properties and passing objects by references has been noted many times, I've just noticed something that appears to be a VB throwback in a new guise that I hadn't seen anyone mention before. Maybe I'm just a conspiracy theorist (I don't know anyone in the relevant teams), but whether or not this theory is true, I think it's a good story regardless.

I'm currently working on a project that's finally forced me to start learning WPF. Of course I've seen the snazzy demos with videos on spinning cubes, but up until now I never really had the time (or more importantly the necessity) to figure out how it all worked. Now I've only just dipped my toes into the water, but so far I'm blown away by both the capabilities and the elegance of the architecture.

Once you start looking at WPF, it doesn't take long before you hear about this thing called XAML. At first glance, XAML is the XML language you use to build WPF GUIs. While there are fancy WPF designers in Visual Studio 2005 (via CTP tools) and Expression Blend, ultimately these are just editors over XAML files, and I've found that, just like with HTML, learning how to write XAML by hand is a great way of getting a better appreciation and understanding of the technology. If you haven't seen XAML code before, there are stacks of WPF XAML examples here, amongst other places.

However after reading and playing with XAML a bit more, I had the "a-ha" moment when I started to understand that XAML isn't actually about WPF at all. While the two technologies taste great together, you are completely free to build WPF apps entirely in code without a line of XAML. More interestingly, you can use XAML to build things completely unrelated to WPF. This is because XAML is actually a language for defining graphs of arbitrary .NET objects. While there are a few gotchas (like the requirement for classes to have default public constructors), XAML can be used for a wide array of applications, even when there isn't a UI to be seen.

To test this theory, I thought I'd try building a Windows Forms application in XAML. Obviously this wasn't the scenario that XAML was built for, but since all of the key classes are well behaved in terms of their constructors and collection types, it all worked just like a bought one. Here is the XAML for my trivial Windows Form:

 <wf:Form x:Class="XamlWinForms.Window1"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms" 
    xmlns:sys="clr-namespace:System;assembly=mscorlib" 
    Text="Window1" Height="300" Width="300"
    >
  <wf:Form.Controls>
    <wf:Panel BackColor="#00FFFF" Dock="Fill" BorderStyle="Fixed3D">
      <wf:Panel.Controls>
        <wf:Button Text="Click Me!" Left="50" Top="50" Width="100" Height="50" Click="Button_Click"></wf:Button>
        <wf:ListBox Top="120" Left="20">
          <wf:ListBox.Items>
            <sys:String>Foo</sys:String>
            <sys:String>Bar</sys:String>
          </wf:ListBox.Items>
      </wf:ListBox>
      </wf:Panel.Controls>
    </wf:Panel>
  </wf:Form.Controls>
</wf:Form>

You would never do this in a real application, mainly due to the lack of visual designers, plus the need to specify co-ordinates for everything makes it much more painful than writing WPF applications by hand. But still, after admiring my work, it got me thinking that this is actually a far more sensible representation for a GUI, even in a WinForms app, than what Visual Studio does by default. Visual Studio's approach is to use the designer data to generate code (such as C# or VB) that explicitly adds all of the controls to the form and sets all of the properties. Even though this code is now safely hidden away in generated partial classes, it's all a bit fragile and, to me at least, feels unnatural - especially when it comes to parsing the code to re-render the form in the visual designer.

But then it occurred to me that I've seen a very similar approach to declaratively specifying forms before, in - you guessed it - Visual Basic 4.0 to 6.0. I don't actually have any of my old projects lying around on my hard disk anymore, but a quick search of the web came up with a number of examples of .FRM files, with code like this:

 VERSION 5.00
Begin VB.Form Form1 
   Caption         =   "Form1"
   ClientHeight    =   3090
   ClientLeft      =   60
   ClientTop       =   450
   ClientWidth     =   3690
   ForeColor       =   &H0000FFFF&
   LinkTopic       =   "Form1"
   MaxButton       =   0   'False
   ScaleHeight     =   3090
   ScaleWidth      =   3690
   StartUpPosition =   3  'Windows Default
   Begin VB.Timer Timer1 
      Interval        =   1000
      Left            =   3000
      Top             =   2280
   End
   Begin VB.CommandButton Command1 
      Caption         =   "Press to Play"
      BeginProperty Font 
         Name            =   "MS Sans Serif"
         Size            =   9.75
         Charset         =   0
         Weight          =   700
         Underline       =   0   'False
         Italic          =   0   'False
         Strikethrough   =   0   'False
      EndProperty
      Height          =   495
      Left            =   720
      MaskColor       =   &H008080FF&
      TabIndex        =   0
      Top             =   2400
      Width           =   2175
   End
   Begin VB.Shape Shape1 
      FillColor       =   &H000000FF&
      FillStyle       =   0  'Solid
      Height          =   615
      Index           =   8
      Left            =   2280
      Shape           =   5  'Rounded Square
      Top             =   1080
      Width           =   495
   End
End

This file format was defined before the days of XML, but if you look at the content it has an uncanny resemblance to the XAML in its ability to define controls and properties, nest objects in one another, and even mix controls and (rudimentary) graphics together. I know that the XAML team has spent a bunch of time taking this idea and moving it far, far beyond what was ever possible in those days - but it's nice to know that good ideas like this don't die, they are just cryogenically frozen, waiting for just the right era to be thawed out again.

Comments

  • Anonymous
    June 20, 2007
    Have you already had a look at Acropolis. It actualy also uses XAML outside the GUI, for wiring the 'parts' etc. together. XAML is also used as specification, which can then be used/consumed by a tool to transform to different level/view.

  • Anonymous
    June 20, 2007
    Holi Me gustaria saber de que se trata el Blog. no entiendo mucho. Me podrias explicar de que se trata. No hablo ingles pero se ve interesante. Chaooooo escribeme

  • Anonymous
    June 20, 2007
    At least as early as VB3, these textual .frm files existed. You could also save as the binary equivalent, but this was discouraged due to instability and corruption.

  • Anonymous
    June 22, 2007
    Nice work Tom! Just to drive this home further, for those that are not familiar with Windows Workflow Foundation, it uses XAML (XOML) as well for defining business processes. (see the snippet below) <SequentialWorkflowActivity x:Class="XAMLWorkflow.Workflow1" x:Name="Workflow1" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">    <IfElseActivity x:Name="ifElseActivity1">        <IfElseBranchActivity x:Name="ifElseBranchActivity1">            <IfElseBranchActivity.Condition>                <CodeCondition Condition="EvalCondition" />            </IfElseBranchActivity.Condition>            <CodeActivity x:Name="codeActivity1" ExecuteCode="codeActivity1_ExecuteCode" />            <FaultHandlersActivity x:Name="faultHandlersActivity1">                <FaultHandlerActivity x:Name="faultHandlerActivity1" Fault="{ActivityBind Workflow1,Path=faultHandlerProp}" FaultType="{x:Type System.NullReferenceException}">                    <CodeActivity x:Name="codeActivity3" ExecuteCode="codeActivity3_ExecuteCode" />                </FaultHandlerActivity>            </FaultHandlersActivity>        </IfElseBranchActivity>        <IfElseBranchActivity x:Name="ifElseBranchActivity2">            <CodeActivity x:Name="codeActivity2" ExecuteCode="codeActivity2_ExecuteCode" />        </IfElseBranchActivity>    </IfElseActivity> </SequentialWorkflowActivity>

  • Anonymous
    June 22, 2007
    The comment has been removed

  • Anonymous
    June 27, 2007
    My memory of the glory days of Windows 3.x development is a little hazy now, but I thought textual forms were part of the 'visual' range of tools, so not strictly VB-specific.  If I remember rightly, forms in those days were part of the resources group.  At that time there was no specific documentation of the contents of a .frm file (at least, I never found anything...), but it was often easier to tweak form files by hand for small changes, rather than power up the form designer.

  • Anonymous
    September 14, 2007
    Interesante &quot;correspondencia&quot; entre XAML y los .FRM de los viejos (que aun utilizo) proyectos