Earlier this year I wrote about my 20-40 program with Sammamish Rowing Association.
I had a great 4 months getting back into rowing. This weekend I rowed in my first Masters Regional Regatta in Vancouver, WA. It was a good end to my first season back rowing. I rowed in two quad races (advancing out of the heats to the finals in 1) and one double race (we missed qualifying for the finals by less than 2 seconds.).
I'm going to continue to row year round, as I'm really enjoying being back in the boat, and I'm looking foward to what a full year of training and practice can do to my rowing/racing. I'm going to try to increase the number of workouts that I can fit in outside of rowing days, so that I can give it 100%.
This isn't the same thing as a Rob Day (which I've been marginally successful taking every month), but serves the same purpose.
(Thanks to my wife, who tolerates me waking up insanely early 3 days a week.)
[Beta 1 of .NET 4 has released, and we’ve been doing a series of blog posts describing new XAML functionality.]
One of the things that most excites me about System.Xaml.dll is the flexibility that our programming model gives to people who need something extra from XAML. You may already know that we've componentized XamlReader.Load() into a component that reads XML and produces XAML nodes (XamlXmlReader) and a component which takes XAML nodes and creates an object graph (XamlObjectWriter).
These readers and writers have base classes (System.Xaml.XamlReader and System.Xaml.XamlWriter) which define a model of XamlReaders which produce XAML nodes and XamlWriters which consume XAML nodes and do something interesting. The model is similar to XmlReader and XmlWriter from System.Xml.dll.
So what is a XAML node?
We have 7 XamlNodeTypes:
-
StartObject - Signifies the start of an object instance in XAML. This is an object element start tag or a markup extension (inside an attribute value).
-
EndObject - Signifies the end of an object instance in XAML. This is an object element end tag or a markup extension close (inside an attribute value).
-
StartMember - Signifies the start of a member (property, event, attached property, attached event, or directive). These are represented in markup as attributes or property elements.
-
EndMember - Signifies the end of a member.
-
Value - Attribute values or text nodes in the XamlXmlReader's case.
-
Namespace - Signifies the definition of a namespace and prefix pair. These come before the StartObject that they are specified on in XAML's XML syntax.
-
GetObject - Signifies the start of an object instance in XAML. This occurs for r/o collections or r/w collections without an explicit collection element.
XamlReader and these nodes define the Data Model for XAML - which I like to call “Objects - Members - Values.”
Things you can do in a XAML node loop
Writing a XAML node loop can walk through the set of nodes that come from a XamlReader. It can then choose to do one of many things:
-
evaluate the data, report results. (for example: a validator)
-
pass the XAML nodes to a writer (like XamlObjectWriter). (you could build XamlPad like this...perhaps you'd want to strip out x:Class and any events...better than XamlPads of today)
-
pass the XAML nodes to a writer and adding additional nodes. The Workflow designer adds linenumber and lineoffset information as attached properties to enable better debugging at runtime.
-
more...
Example of finding all named object instances
I built an example that uses a XAML node loop to help answer a WPF forum question "How to get x:Name from 3DElements using XamlReader.Load".
By using XamlXmlReader and XamlObjectWriter, and keeping track of names and instances of objects, we’re able to solve the scenario.
[Will upload this sample to http://robrelyea.com soon…]
1: //This .NET 4 Beta 1 example was inspired by the WPF forum question at:
2: // http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5c226430-c54d-45b8-a8a2-7e4a79e3692a
3: //
4:
5: /*
6: Console output of this example is:
7: XAML Contents:
8: <Window
9: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
10: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
11: xmlns:local="clr-namespace:NodeLoopExample;assembly=NodeLoopExample"
12: >
13: <StackPanel>
14: <Button Name="button1">Ok</Button>
15: <Button x:Name="button2">No, it is not ok!</Button>
16: <Button>
17: <Button.Background>
18: <LinearGradientBrush x:Name="brush">
19: <GradientStop Color="AliceBlue" />
20: <GradientStop Color="Red" Offset="1" />
21: </LinearGradientBrush>
22: </Button.Background>
23: Button with color
24: </Button>
25: </StackPanel>
26: </Window>
27:
28: NamedObjects:
29: Name: button1, Type: Button
30: Name: button2, Type: Button
31: Name: brush, Type: LinearGradientBrush
32: --close the window to close the app--
33: */
34:
35: using System;
36: using System.Collections.Generic;
37: using System.Windows;
38: using System.Xaml;
39: using System.Xml;
40: using System.IO;
41:
42: namespace NodeLoopExample
43: {
44: class Program
45: {
46: [STAThread]
47: static void Main(string[] args)
48: {
49: Console.WriteLine("XAML Contents:");
50: string xamlContents = File.ReadAllText("WindowWithNames.xaml");
51: Console.WriteLine(xamlContents);
52: Console.WriteLine();
53:
54: List<Frame> namedObjects = ShowObjectGraphAndHarvestNames("WindowWithNames.xaml");
55: Console.WriteLine("NamedObjects:");
56: foreach (Frame frame in namedObjects)
57: {
58: Console.WriteLine("Name: {0}, Type: {1}", frame.Name, frame.Type.UnderlyingType.Name);
59: }
60:
61: Console.WriteLine("--close the window to close the app--");
62: Application app = new Application();
63: app.Run();
64: }
65:
66: //Let's loop through all the XAML nodes in this XAML file.
67: //We'll keep track of the tag name (Type), attributes or property elements (Member)
68: // names (Name) and instances (Instance) on a Frame class.
69: //We'll return all Frames with a name from this method.
70: //We also want to show the objectGraph created.
71: private static List<Frame> ShowObjectGraphAndHarvestNames(string fileName)
72: {
73: //we use a stack to keep track of names/instances
74: Stack<Frame> stack = new Stack<Frame>();
75:
76: XmlReader xr = XmlReader.Create(fileName);
77: XamlXmlReader reader = new XamlXmlReader(xr);
78: XamlObjectWriter writer = new XamlObjectWriter(reader.SchemaContext);
79:
80: //List of all frames which had names
81: List<Frame> namedObjects = new List<Frame>();
82:
83: while (reader.Read())
84: {
85: writer.WriteNode(reader);
86:
87: switch (reader.NodeType)
88: {
89: case XamlNodeType.StartObject:
90: Frame newFrame = new Frame();
91: newFrame.Type = reader.Type;
92: stack.Push(newFrame);
93: break;
94: case XamlNodeType.GetObject:
95: Frame newFrameForGet = new Frame();
96: newFrameForGet.Type = stack.Peek().Member.Type;
97: stack.Push(newFrameForGet);
98: break;
99: case XamlNodeType.StartMember:
100: stack.Peek().Member = reader.Member;
101: break;
102: case XamlNodeType.EndMember:
103: stack.Peek().Member = null;
104: break;
105: case XamlNodeType.EndObject:
106: stack.Peek().Instance = writer.Result;
107: if (stack.Peek().Name != null)
108: {
109: namedObjects.Add(stack.Peek());
110: }
111: stack.Pop();
112: break;
113: case XamlNodeType.Value:
114: XamlMemberBase contentProperty = stack.Peek().Type.GetAliasedProperty(XamlLanguage.Name);
115: if (stack.Peek().Member == contentProperty
116: || stack.Peek().Member == XamlLanguage.Name)
117: {
118: stack.Peek().Name = reader.Value as string;
119: }
120: break;
121: }
122: }
123:
124: object rootObject = writer.Result;
125: ShowInWindow(rootObject);
126: return namedObjects;
127: }
128:
129: private static void ShowInWindow(object root)
130: {
131: Window window = root as Window;
132: if (window == null)
133: {
134: window = new Window();
135: window.Content = root;
136: }
137: if (window.Title == "")
138: {
139: window.Title = "NodeLoopExample";
140: }
141: window.Height = 400;
142: window.Width = 300;
143: window.Top = 400;
144: window.Left = 400;
145: window.Show();
146: }
147: }
148: class Frame
149: {
150: public XamlType Type { get; set; }
151: public XamlMemberBase Member { get; set; }
152: public string Name { get; set; }
153: public object Instance { get; set; }
154: }
155: }
Sparky Dasrath writes a short post discussing XAML centric improvements in VS2010 XAML Editor and Property Grid for WPF and Silverlight developers.
I was working on a draft of a post about Events and XAML, and I tripped over this blast from the past from Kevin Dente from 2003 “Longhorn and Avalon”
I predict that Avalon will be a smashing success with developers. Why? Because XAML is so darn fun to say. Zaml. Just kind of rolls off the tongue, doesn't it? Coupled with its partner in crime - BAML - it's got a one-two punch that just can't miss. Way more fun to say than SVG. Or XUL. Yep, best technology name since SCSI.
XAML BAML, baby.
It reminds me of my “Name Fluency” post from May 2006:
I was reading an article in the NY Times this morning and I ran across the term "name fluency".
The article discussed a study that looked at stock performance based on a number of issues included how pronounceable the name was.
Although I had never heard a term for this before now, I'm a big believer in name fluency. Back when we had to pick a name for Avalon's markup language, many names were considered. I favored XAML (eXtensible Avalon Markup Language). A coworker was arguing for AXML (Avalon XML).
Name fluency was my reasoning.
Shortly before our largest customer preview of Avalon/XAML, perhaps in 2003, we decided to make the A stand for Application, since we didn't think the term Avalon was going to ever be shared externally.
I received a customer request for how a XAML downloaded from a server can still have events. Let’s discuss the options for .NET 3.x, 4 and Silverlight.
Option 1: Compile your XAML (works in v3, v4, and Silverlight)
By default, when you add a XAML page into a project in VS or Blend, its BuildAction (shown in the properties pane – F4) is Page. When you build the assembly, MarkupCompilePass1 and MarkupCompilePass2 will analyze all the Pages and generate generated code files (.g.cs, .g.vb, etc…) and .baml files. When you navigate to the url of the XAML or do a new of the class defined in the XAML, it will end up calling Application.LoadComponent, which will load the class and the baml file. Every element in XAML that has a name or an event handler declared will end up calling IComponentConnector.Connect() in the generated code file, where we will wire the field that matches any name on that element, and wires any events. I can go deeper in this space if necessary, but you could also read this old post: “XAML, BAML, .g.cs details”
For Silverlight, there is no BAML, but we still create a generated code file and wire named objects to fields. Event wire up is handled by the parser.
Option 2: Don’t send UI from server, send data (works in v3, v4, and Silverlight)
Often people are used to sending HTML + Script from the server to the client. Since WPF (and Silverlight) has great databinding capabilities, you should rethink what you actually need to send down to the client for this kind of scenario. Often it is the data that changes often, and the UI is more static. You could Databind to downloaded XML data in an XmlDataProvider object.
Option 3a: Use XamlReader.Load() (no compiling) and specify event handlers in XAML (works in v4 and Silverlight)
In .NET 4, we have replaced the XAML plumbing for WPF. One of the new capabilities is that XamlReader.Load can handle event attributes declared in XAML. V3 used to throw a parse exceptions.
<Button Click="handle_ok">Ok</Button>
V4 will look for an method on the root object of the XAML file called handle_ok. So, if you know the set of methods you’ll have, you could send down a XAML with the appropriate root object and specify events as attributes in the XAML.
Option 3b: Use XamlReader.Load() (no compiling) and specify event handlers with a MarkupExtension (works in v4)
If having the methods located on the Root object doesn’t work for your scenario, v4 allows you to provide any markupextension that will return a Delegate as the value for an event in XAML.
<Button Click="{Run MyRoutine,Ok}">Ok</Button
You could build the RunExtension class so that it finds MyRoutine anywhere you want. You can also pass along parameters to that event, as you please.
Option 3c: Use XamlReader.Load() (no compiling) and specify event handlers with a DLR language via a markup extension (works in V4)
One could build a markupextension that can run code, perhaps with the DLR.
<Button Click="{RunCode 'textBox1.Text = lastName.Text + ", " + firstName.Text;'}">ok</Button>
The RunCodeExtension would need to know how to call into the DLR, and it would also need to use IXamlNameResolver to have access to the set of named objects that might be refered to in code.
Option 4: Integrate the DLR via a markup extension (works in v3 and v4)
In 2008, Daniel Paul wrote a 6 part series that explores adding DLR code into XAML. Part 5 explores writing Event handlers.
Option 5: Use XamlReader.Load, and wire events with FindName afterwards (works in v3)
See style #2 in “3 Coding Styles for Avalon Applications”
Internal thread that may be of use to more people:
Question From: Microsoft Developer
Is there a way to configure XAML writer (XamlWriter.Save() or XamlServices.Save()) to not to serialize null properties. Right now I get "{x:Null}" written for them?
Answer From: XAML Team Developer
You need to attribute the affected properties with [DefaultValue(null)]
Mike Hillberg's "Being Written by XamlWriter" is a good read for this kind of info
--
Krishna Bhargav shows how to declare String.Empty() in XAML in “Declaring Empty String in XAML”. XAML 2009 will continue with this same behavior.
XAML 2006 Background
XAML design in .NET 3 was mostly driven by WPF scenarios. In that timeframe, WPF only had one significant generic type that required its use in XAML: PageFunction<T>. As such, we supported x:TypeArguments on the root element of compiled XAML files. We knew there were 2 further steps for Generic support to do, but skipped them for v3:
- Support instantiation of a generic type in any XAML load. (coming in XAML 2009)
- Support providing x:TypeParameters to compiled XAML. (not coming in XAML 2009)
XAML 2009 Support for Generic Types
Since .NET 4 is seeing XAML usage broaden into other areas with System.Xaml.dll and XAML 2009 language features, it became more important for XAML to support Generic types (a CLR 2 feature!).
This example uses WPF generic types (just because I’m most adept with those tags):
<Window>
<Window.DataContext>
<ObservableCollection x:TypeArguments="my:Person">
<my:Person FirstName="Tom" LastName="Holiday" />
<my:Person FirstName="Joan" LastName="Holiday" />
</ObservableCollection>
</Window.DataContext>
…
</Window>
This could be accomplished in C# by:
Window win = new Window {
DataContext = new ObservableCollection<Person> {
new Person { FirstName="Tom", LastName="Holiday" },
new Person { FirstName="Joan", LastName="Holiday" }
}
};
(thanks to Dave's comment who gave me more concise C# syntax and Simon's comment who removed an extra "new").
Multiple Type Arguments
In order to support multiple type arguments, use a comma to delimit:
<Dictionary x:TypeArguments="x:String, x:Double">
…
</Dictionary>
Nesting of Type Arguments
If you wanted to have a Dictionary of Strings map to lists of Doubles, you would use parenthesis (since <> are kindof taken in XML):
<Dictionary x:TypeArguments="x:String, sys:List(x:Double)">
…
</Dictionary>
Node Stream Representation
For those of you looking at the nodes that XamlXmlReader (or other XamlReaders) produce, x:TypeArguments appears to disappear from the stream of nodes. This is by design…a XamlReader would expose the ObservableCollection element above as:
- xamlReader.NodeType: StartObject
- xamlReader.Type: ObservableCollection(my:Person)
In the PDC2008 XAML talk, we go over the Node Stream…but I haven’t blogged about it yet…
Remember
Most XAML 2009 Features won’t work in compiled XAML scenarios in .NET 4, but will work with uncompiled XAML. See details here…”Yes, XAML2009 isn’t everywhere yet…”
In the Beta2 of .NET 4, we’re working on type forwarding several types from WindowsBase.dll to System.Xaml.dll. WindowsBase will have a dependency on System.Xaml. System.Xaml will no longer depend on WindowsBase.
On Friday we discovered some issues with Cider/Blend that we’ll have to work with those teams to resolve.
My guess is that these 2 tools have needed to differentiate between Silverlight and .NET’s ContentPropertyAttribute…and have probably moved to use the full name of the type.
Unfortunately, full name comparisons don’t respect TypeForwardedToAttributes.
Wouldn't it be nice if packaging/specs for all electronics goods had a standard way of listing their power use when on, standby, etc...
I'm looking to buy a new monitor for home, and found this list helpful: http://reviews.cnet.com/green-tech/monitor-comparison-chart/?tag=contentBody;nextPage
Anson, a WPF Program Manager, has great knowledge of the direction WPF to help touch enable your WPF applications. Watch the Channel 9 video "Multi-touch in WPF 4 Beta 1" and follow up with your questions/comments on that page.
Beta1 of WPF4 has some, but not all of the Multi-Touch features coming to you in WPF4.
HTML provides a simple way to do references from one property to another object easily.
<LABEL FOR="moreinfo">
send more information
<INPUT NAME="moreinfo" TYPE=CHECKBOX ID="moreinfo">
</LABEL>
From HTMLCodeTutorial.com
We wanted XAML Vocabularies to have the same simplicity (and some more capabilities), so that is why we have invested in Name References in XAML2009 and System.XAML.
Name references should work as backwards or forwards references.
Type Authors – Enable Reference by Name for appropriate Properties
Label.Target is a UIElement, however we’d like to enable a simple Name reference to other objects declared in XAML.
<Label Target="firstName" >_First name:</Label>
<TextBox Name="firstName" />
In order to enable users to do this, type authors should use System.Xaml’s NameReferenceConverter on your property.
[TypeConverter(typeof(NameReferenceConverter))]
public UIElement Target
{ … }
Luke put this example of what he’d like to do in a comment on my blog:
<Table Name="Customer"/>
<Table Name="Order"/>
<Relationship From="Customer" To="Order" Cardinality="OneToMany"/>
See “Code Sample using NameReferenceConverter” at the bottom of this post that implements Table, Relationship and demos them.
XAML Users – Use a reference to another object anywhere
XAML2009 introduces the a new built-in markup extension called {x:Reference}. Using it, you can explicitly set the value of the target property with a reference to the named object. You can also use it as an object element which can reside in a collection.
If From/To didn’t use NameReferenceConverter (as described above), the XAML author could do this:
<Table Name="Customer"/>
<Table Name="Order"/>
<Relationship From="{x:Reference Customer}" To="{x:Reference Order}" Cardinality="OneToMany"/>
Type Authors – Build more complex minilanguages with integrated Name support
Somebody may want to build an expression engine that could “dot down” to arbitrary properties of objects like this:
<Button Height="{Expression namedObject1.Height + namedObject2.Height / 2}"/>
A markup extension or type converter could call GetService(typeof(IXamlNameResolver)) in order to get access to a service to search for named objects already encountered, or register a request for an object that hasn’t been seen yet. A sample of this may be worthy of another post.
Creating documents with x:Reference
XamlServices.Save() will add x:Reference as appropriate, based on the object graph you pass it.
Summary
Named references in XAML2009 is an important feature, helping to enable a number of scenarios for different XAML Vocabularies. We hope you enjoy.
(Please see “Note – What works where” at the very bottom of this post.)
Code Sample using NameReferenceConverter
Requires Beta1 of .NET 4.
(Command Line project with WindowsBase.dll and System.Xaml.dll as additional assembly references).
1: using System;
2: using System.Collections.Generic;
3: using System.ComponentModel;
4: using System.Windows.Markup;
5: using System.Xaml;
6:
7: namespace ReferenceExample
8: {
9:
10: //when run, this program creates the following output:
11: /*
12: <DatabaseCollection Capacity="4" xmlns="clr-namespace:ReferenceExample;assembly=ReferenceExample">
13: <Table Name="Customer" />
14: <Table Name="Order" />
15: <Relationship Cardinality="OneToMany" From="Customer" To="Order" />
16: <Relationship Cardinality="OneToOne" From="Customer" />
17: </DatabaseCollection>
18: */
19:
20: class Program
21: {
22: static void Main(string[] args)
23: {
24: Table t1 = new Table();
25: t1.Name = "Customer";
26: Table t2 = new Table();
27: t2.Name = "Order";
28: Relationship r1 = new Relationship();
29: r1.From = t1;
30: r1.To = t2;
31: r1.Cardinality = Cardinality.OneToMany;
32: Relationship r2 = new Relationship();
33: r2.From = t1;
34:
35: DatabaseCollection dc = new DatabaseCollection();
36: dc.Add(t1);
37: dc.Add(t2);
38: dc.Add(r1);
39: dc.Add(r2);
40:
41: string xamlString = XamlServices.Save(dc);
42: Console.WriteLine(xamlString);
43:
44: Console.WriteLine("--press any key--");
45: Console.ReadKey();
46: }
47: }
48:
49: public abstract class DatabaseObject {}
50:
51: public class DatabaseCollection : List<DatabaseObject> {}
52:
53: [RuntimeNameProperty("Name")]
54: public class Table : DatabaseObject
55: {
56: public string Name { get; set; }
57: }
58: public class Relationship : DatabaseObject
59: {
60: [TypeConverter(typeof(NameReferenceConverter2))]
61: [DefaultValue(null)]
62: public Table From { get; set; }
63:
64: [TypeConverter(typeof(NameReferenceConverter2))]
65: [DefaultValue(null)]
66: public Table To { get; set; }
67:
68: public Cardinality Cardinality { get; set; }
69: }
70:
71: public enum Cardinality
72: {
73: OneToOne,
74: OneToMany,
75: ManyToMany,
76: }
77:
78: //In .NET 4 Beta1, System.Xaml.NameReferenceConverter doesn't have ConvertTo/CanConvertTo implemented.
79: //Working around with a version hard coded for this scenario...
80: public class NameReferenceConverter2 : NameReferenceConverter
81: {
82: public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
83: {
84: return destinationType == typeof(string);
85: }
86: public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
87: {
88: Table table = value as Table;
89: return table.Name;
90: }
91: }
92:
93: }
[Note – what works where]
In .NET 4 Beta1, NameReferenceConverter + IXamlNameResolver should be mostly functional (we’ve fixed a few bugs since). {x:Reference} and <x:Reference /> won’t work when you compile XAML, but we plan to address this in .NET 4 (we believe that moving x:Reference from System.Xaml.Replacements to System.Windows.Markup will just make that work in the compiler). Cider/Blend will likely won’t work initially. See “Yes, XAML2009 isn't everywhere yet”
[This post was originally posted on November 29, 2004 and may still be available via this link. I’m reposting to ensure that it remains available. In 2008, I wrote an updated “8 Benefits of XAML for UI and Beyond”]
I like the description that Karsten, Tim, and Arik wrote about XAML from the What's New in the "Avalon" Community Technology Preview article:
XAML. "Avalon" also introduces XAML, a markup language to declaratively represent user interface for Windows applications, improving the richness of the tools with which developers and designers can compose and repurpose UI. For Web developers, XAML provides a familiar UI description paradigm. XAML also enables the separation of UI design from the underlying code, enabling developers and designers to work more closely together.
On top of that, I thought it would be interesting to share the 7 major goals we had in mind while designing XAML. Generally, many design decisions require balancing the different goals (as they often conflict).
Be XML
All valid XAML files must be valid XML files. The opposite isn't always true…all XML files are not XAML files. This is important because of the ecosystem of tools, systems, APIs and developers familiar with XML.
Describe Hierarchy of Objects in a Human Readable/Writable Way
Markup provides a concise way to represent a set of objects arranged in a hierarchy. It is more readable and writable than programming languages. It is the best format to represent the initial state of an object hierarchy.
Provide Page-Based Programming Model
Like DHTML + ASP.NET, XAML provides a way for you to associate programming code with the declarative markup. We recommend people having a code behind file (.xaml.vb or .xaml.cs for example.), but also support code being directly embedded inside of a XAML file. XAML and any .Net language can work together in this page-based programming model. The .Net Language needs to support CodeDOM and a set of language specific MSBuild target files. In this CTP, we support C# or Visual Basic. We will likely add J# support by spring and we look forward to supporting other languages from Microsoft (C++ and JScript) and other companies in the future.
Be Source Code or Runtime Instructions
Sometimes XAML is treated as source code, that gets compiled into an assembly (.exe or .dll) as a combination of a binary representation and IL. Other times, it is interesting to build XAML at a later time and interpret it at runtime. While we love the benefits that a markup representation give developers, we prefer to deal with XAML at compile time, not run time.
Take Advantage of Strong-Typing
Objects that have a strongly-typed OM (object model) are better systems to program with. DHTML is a system that was very string-based, and thus difficult to debug. Systems that leverage XAML (including Avalon), get the benefit of using strings in markup, but can get compile time errors for markup or code. XAML's default is that it must understand every tag and attribute. HTML defaults to ignoring any mistyped element name, attribute name or attribute value. While there is a place for this ignoring to allow for forward compatibility, we'll provide a different mechanism for this.
Be Toolable
Systems described in XAML will be creatable and consumable by a wide set of tools. We hope to have a clear & minimal set of rules on how classes get represented in markup. We hope to encourage an ecosystem of tools.
Be Useful for Much More than UI Definitions
While XAML will be heavily used in the vast majority of Avalon applications or documents, its uses will be many. I'm writing a command line tool right now that uses a vocabulary of classes in a XAML file used as data to drive the application. I'm getting the following benefits over just using XML to represent this data: 1) validation of my data file without having to write a schema and using a validating xml reader; 2) my code that needs to interact with this data, does it in a strongly typed way; Intellisense works in my code behind; 3) my system has built in extensibility, instead of being tied to specific tag names, I'm tied to a specific class (and subclassing allows others to provide other specializations of that class.) 4) etc… (When this tool is done, I plan on sharing it)
Don't Forget Why We Built XAML - Avalon!
That all being said, I believe it is important to remember that for as interesting as XAML itself may be to some, we are building a comprehensive platform with Avalon. Some people blog excitedly about XAML…however, many of them are actually discussing the power of Avalon, not XAML. XAML is a way to use declarative markup with a set of CLR classes. We're investing much more R&D in the Avalon API and Avalon infrastructure than we are in the parser and markup compiler.
Some Related Previous XAML Posts
Josh Twist has an interesting post arguing that XAML writability is very important, and that many people want to edit XAML directly.
While we have focused on ease of human authoring of XAML as a goal, it has always been balanced with other goals, like toolability. Some quotes:
His two examples of things that could improve WPF hand authoring of XAML:
- RowDefinitionCollection, ColumnDefinitionCollection could both have a type converter associated with them to support a syntax like that.
- Transform used to have a type converter to make ScaleTransform, RotateTransform easier that we removed late in 3.0…yes, a markup extension could also be used.
Yes, we have a bit of a love/hate relationship with minilanguages. We need to reevaluate the pros/cons of minilanguages (as Mike Hillberg was just mentioning the other day) with the XAML team, the WPF/Silverlight team, and XAML based tools teams.
In these cases, there are things that type authors can do (add a type converter), things that developers can do (build a type converter), and future things we could do in the XAML language.
I’m interested to see your opinions on the issues that Josh brings up in his post.
Jaime posted a good list of features in WPF4, including what is in Beta1 and what is coming later.
Next page »