Using the Windows Forms XML Parser Sample

Using the Windows Forms XML Parser Sample

by Joe Stegman

Introduction

Basic Sample

Markup Reference

Markup Parser Reference

Introduction

This is a sample of an extensible mechanism to add a markup model on top of an existing .NET Framework object model.  This sample’s parsing rules can be summarized as “XML elements map to .NET Framework types and XML attributes map to Type properties (or events)”.  This sample includes a markup parser that dynamically generates an object instance tree from an XML file.  The markup format includes constructs for the following:

• XML Namespace to .NET Framework Namespace mapping
• Object Instancing
• Object Identification and References
• Property Sets
• Instance and Static method invocation
• Event Wire-Ups
• Assembly References

Disclaimer

This is only a sample and will not be part of the next version of Windows Forms. In addition, this sample was written against the .NET Framework version 1.1 and has not been tested against other versions.

Basic Sample

The following sample shows the XML syntax used to declare a simple Windows Forms Form with a single child Label Control.

xml version="1.0" encoding="utf-8" ?>

mapping xmlns="http://www.microsoft.com/2003/WindowsForms"

namespace="System.Windows.Forms;System.Drawing"?>

<wfml xmlns="http://www.microsoft.com/2003/WindowsForms"

xmlns:wfml="http://www.microsoft.com/2003/WFML">

<Form wfml:root="true" Text="Basic Sample" Size="300,200">

<Label Text="Hello World" AutoSize="True" Location="10, 20"/>

<method.Show/>

Form>

wfml>

The Windows Forms XML parser sample will generate an instance tree (Form) from the above XML.  This assumes the above XML is contained in a file named “sample.xml”.

MarkupParser  parser = new MarkupParser();

object        form = parser.Parse("basic.xml");

This will dynamically generate the following Form:

Dissecting the Basic Sample

The basic sample is composed of an XML declaration, a Windows Forms parser specific processing instruction, a root tag, the instance declarations and an end tag.  These sections are described below:

XML Declaration

xml version="1.0" encoding="utf-8" ?>

This is a standard XML declaration that describes the XML version and encoding.  This line is at the top of most XML files and is not specific to this sample.

Sample Processing Instruction

mapping xmlns="http://www.microsoft.com/2003/WindowsForms"

namespace="System.Windows.Forms;System.Drawing"?>

This line defines a mapping between an XML namespace and .NET Framework namespaces.  This line declares that any elements defined in the XML namespace “http://www.microsoft.com/2003/WindowsForms” will map to types in the .NET Framework namespaces “System.Windows.Forms or System.Drawing”.  See the Markup reference section for more information on the mapping processing instruction.

Root Tag

<wfml xmlns="http://www.microsoft.com/2003/WindowsForms"

xmlns:wfml="http://www.microsoft.com/2003/WFML">

This line defines the default XML namespace for the sample file (“http://www.microsoft.com/2003/WindowsForms”) and defines “wfml” as a prefix for elements and attributes in the “http://www.microsoft.com/2003/WFML” namespace.

Instance Declarations

<Form wfml:root="true" Text="Basic Sample" Size="300,200">

<Label Text="Hello World" AutoSize="True" Location="10,20"/>

<method.Show/>

Form>

When processing this XML, the parser will create an instance of type Form using the default Form constructor and set its Text property to “Basic Sample” and its Size property set to “300,200”.  The parser will create a “Label” and add it to the Form’s Controls collection (see below for details) and set the Label’s Text property to “Hello World”, set the Label’s AutoSize property to “True” and set the Label’s Location property to “10,20”.  Finally, the parser will call the method “Show” on the Form instance.

XML Namespace to .NET Framework Mappings

The sample parser creates an instance of the System.Windows.Forms.Form type as a result of parsing the

tag.  The .NET Framework version 1.1 includes at least two different “Form” types: one in System.Windows.Forms and one in System.Web.UI.MobileControls.  The parser selected the Form type in System.Windows.Forms based on the evaluation of the XML Namespace to .NET Framework Namespace mappings setup using the “mapping” processing instruction (described above).  In this example, the element is in the default XML namespace.  The default XML namespace is “http://www.microsoft.com/2003/WindowsForms” as specified in the root “wfml” tag:

<wfml xmlns="http://www.microsoft.com/2003/WindowsForms" …

The “mapping” processing instruction mapped this XML namespace to the System.Windows.Forms .NET Framework namespace:

mapping xmlns="http://www.microsoft.com/2003/WindowsForms"

namespace="System.Windows.Forms;System.Drawing"?>

The parser used this mapping to select the Form type in System.Windows.Forms rather than the Form type in “System.Web.UI.MobileControls”.

Collection Heuristics

When the parser encounters a child element, the parser will instantiate the child element based on the mapping rules defined above and then add the instanced element to a collection on the parent (or directly to the parent if the parent is a collection).   By default, the parser looks for a “Controls” collection (which is the only thing Windows Forms specific about the parser) but can add children to a different collection using explicit “dot” notation.  Explicit notation takes the form:

In the example above, the child MenuItems are explicitly added to the “MenuItems” collection on the parent “MenuItem”.  The “property.PropertyName” notation is described in more detail in the Markup reference below.

Markup Reference

The sample parser uses a small set of attributes, elements and processing instructions to control the parsing process.  The attributes and elements live in the XML Namespace "http://www.microsoft.com/2003/WFML" and typically have a namespace prefix of “wfml”.

wfml:ID Attribute

The ID attribute is used to uniquely name an instance of an element.  This ID can be used to reference the instance elsewhere in the markup.  In addition, the parser provides an API to query for an instance based on ID (see the Parser reference for details).  In the example below, the Form is given the name”form1”.

xml version="1.0" encoding="utf-8" ?>

mapping xmlns="http://www.microsoft.com/2003/WindowsForms"

namespace="System.Windows.Forms;System.Drawing"?>

<wfml xmlns="http://www.microsoft.com/2003/WindowsForms"

xmlns:wfml="http://www.microsoft.com/2003/WFML">

<Form wfml:ID="form1" Text="Basic Sample" Size="300,200">

<Label Text="Hello World" AutoSize="True" Location="10, 20"/>

<method.Show/>

Form>

wfml>

The parser “Find” method can be used to retrieve the “form1” instance.

MarkupParser  parser = new MarkupParser();

parser.Parse("basic.xml");

Form  form1 = (Form)parser.Find("form1");

wfml:root Attribute

The root attribute identifies the instance that is returned from the “Parse” method on the parser.  There can only be one element with a root attribute.  In the example below, “form1” is the “root” element.

xml version="1.0" encoding="utf-8" ?>

mapping xmlns="http://www.microsoft.com/2003/WindowsForms"

namespace="System.Windows.Forms;System.Drawing"?>

<wfml xmlns="http://www.microsoft.com/2003/WindowsForms"

xmlns:wfml="http://www.microsoft.com/2003/WFML">

<Form wfml:ID="form1" wfml:root="true" Text="Basic Sample" Size="300,200">

<Label Text="Hello World" AutoSize="True" Location="10, 20"/>

<method.Show/>

Form>

wfml>

The parser “Parse” method will return the “form1” instance:

MarkupParser  parser = new MarkupParser();

Form  form1 = (Form)parser.Parse("basic.xml");

wfml:argument Attribute

When instancing types, the parser uses the type’s default constructor.  There are some types such as Bitmap that do not have a default constructor.  The argument attribute is used to specify a single argument to pass to a non-default constructor.  In the example below, the parser will call the Bitmap(string) constructor with an argument of “C:/image.jpg”.

<Form wfml:root="true" wfml:ID="form1" Name="Form1" Text="Set Background">

<property.BackgroundImage>

<Bitmap wfml:argument="C://image.jpg"/>

property.BackgroundImage>

<method.Show/>

Form>

Note that it is not possible to invoke constructors will more than one argument.

property Element

The general rule of parser is XML elements map to types and XML attributes map to properties.  In XML, attributes take the form:

<Element Attribute="string value"/>

The parser is able to deal effectively with strings for non-string properties by using TypeConverters (System.ComponentModel.TypeConverter).  For example, the BackColor property on Form is of type “System.Drawing.Color” but can be set using a string value:

<Form BackColor="Green"/>

In the example above, the BackColor property is converted from “Green” to a “System.Drawing.Color” using a TypeConverter.  The TypeCoverter model works well when the property value can be represented as a string (e.g. Color) but does not provide a good solution when the property type is more complex (e.g. Image).  The parser uses a “dot” (.) property notation to address more complex property sets.  “Dot” notation takes the form “property.PropertyName”.  The following example shows how to set the BackgroundImage on a Form:

<Form wfml:root="true" wfml:ID="form1" Name="Form1" Text="Set Background">

<property.BackgroundImage>

<Bitmap wfml:argument="C://image.jpg"/>

property.BackgroundImage>

<method.Show/>

Form>

In the example above, the BackgroundImage property on the parent Form is set to the result of the “Bitmap” element evaluation.

method Element

Similar to the “dot” property notation, the parser supports a “dot” method notation.  When the parser sees an element of the form “method.methodName”, it will invoke “methodName” on the parent element instance.  In the following example, when the parser encounters “<method.Show/>”, it will invoke the “Show” method on the “form1” instance.

<Form wfml:root="true" wfml:ID="form1" Name="Form1" Text="Set Background">

<property.BackgroundImage>

<Bitmap wfml:argument="C://image.jpg"/>

property.BackgroundImage>

<method.Show/>

Form>

The parser can call both instance and static methods but cannot call methods with more than one argument.  The following example shows how to invoke a static method will a single argument:

<Form wfml:root="true" wfml:ID="form1" Name="Form1" Text="Set Background">

<property.BackgroundImage>

<method.FromFile Static="System.Drawing.Image">

C://image.jpg

method.FromFile>

property.BackgroundImage>

<method.Show/>

Form>

This calls the Static method “System.Drawing.Image.FromFile” with an argument of “C:/image.jpg”.  The Form’s BackgroundImage is set to the method return value.

wfml:var Element

The parser has limited support for creating and referencing variables.  Any element with a wfml:ID attribute can be referenced as a variable using the wfml:var element.  For example:

<Form wfml:ID="form1" Name="Form1" Text="Simple"/>

<wfml:var Name="form1">

<method.Show/>

wfml:var>

In the example above, the “wfml:var” element references the variable named “form1” and the “Show” method is invoked on the “form1” instance.

Variable Prefix

Attribute values that begin with “$” are treated as Variable references. <wfml:var wfml:ID="image"> <method.FromFile Static="System.Drawing.Image">C://image.jpgmethod.FromFile> wfml:var> <Form BackgroundImage="$image" Name="Form1" Text="Set Background">

<method.Show/>

Form>

Mapping Processing Instruction

The “mapping” XML processing instruction is used to map XML namespaces to .NET Framework namespaces.  There may be one or more mapping processing instructions in an XML file.  The general form of this instruction is:

mapping xmlns="XMLNamespace" namespace=".NET Namespaces"?>

The.NET Framework namespace attribute contains a list of one or more namespaces separated by a semi-colon.  For example:

mapping xmlns="MyNamespace" namespace="System.Windows.Forms;System.Drawing"?>

When instancing types, the parser will map XML elements in the namespace specified by “xmlns” to .NET Framework types in the Namespaces specified in the “namespace” attribute.

Assembly Processing Instruction

The “assembly” processing instruction adds an assembly reference to the parser.  The “assembly” processing instruction is analogous to adding references in Visual Studio or the /reference C# compiler switch.  The following example shows how to add a reference to the V1.1. System.Data assembly.

assembly name="system.data" version="1.0.5000.0" culture="neutral" PublicKeyToken="b77a5c561934e089"?>

Markup Parser Reference

The parser dynamically generates an instance tree from a XML file.  The parser API is described below.

Parse Method

The Parse method takes either a string argument representing a file or an XMLTextReader.  The Parse method returns the instance of the element containing the “wfml:root” attribute or the instance of the first  element if “wfml:root” is not specified.

The Parser “AddVariable” method adds a named instance to the parser’s internal variable context.  AddVariable” is used for event handler wire-up as well as to create instances of types too complex for parser’s parsing rules.  The following example will generate a Form and wire-up the Form’s Load event:

The parser will recognize “Load” as an event and look for a variable named “me” and wire-up the Form’s Load event to “me’sFormLoadHandler.  The variable “me” is added to the parser variable list by using “AddVariable”:

private void button1_Click(object sender, System.EventArgs e)

{

MarkupParser       parser = new MarkupParser();

// Parse

object      obj = parser.Parse("sample.xml");

}

private void FormLoadHandler(object sender, EventArgs e)

{

}

Find Method

The Find method is used to retrieve a named (wfml:ID) instance value from the parser variable context.  For example, the following sample defines a Form named “form1” with a Button named “button1”:

<Form wfml:root="true" wfml:ID="form1" Text="Find Sample">

<Button wfml:ID="button1"/>

Form>

The Find method can be used to retrieve the instance value of “button1”:

private void button1_Click(object sender, System.EventArgs e)

{

MarkupParser       parser = new MarkupParser();

// Parse (returns form1)

object      obj = parser.Parse("sample.xml");

// Get button1 instance

Button      button1 = parser.Find("button1") as Button;

}

Reset Method

The parser’s variable context (variable list) is shared across multiple instances of the parser (static list).  The Parser’s Reset method will clear the shared variable context.

Status Event

The parser’s Status event provides line by line parsing state information.  Note that this event is useful only in debugging scenarios.

• 本文已收录于以下专栏：

举报原因： 您举报文章：Using the Windows Forms XML Parser Sample 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)