I just saw Kenny Lim's (digitalnetbizz) posting calling out using a CLR object as a property in XAML. Let me give people some background on the feature and some changes we are considering in the future.
Markup==ObjectModel
This is one of the Avalon programming model's key tenets. We wanted our markup model to have a logical mapping between every Tag and Attribute in XAML and the .Net classes that implement that functionality.
In this example:
<Button Background="Red" Click="clickhandler">Ok</Button>
Avalon will do the following:
1) Create an instance of the System.Windows.Controls.Button class
2) Using the FromString capabilities of the Brush type converter to convert "Red" into a red brush object
3) Set the Background property of button instance to the red brush object
4) Add an event handler to the button's click event that calls the "clickhandler" routine that the user defines in C#/VB/or any language they choose.
5) Call IAddChild.AddText("Ok") on the Button. The Button is responsible for implementing this interface if it wants to handle text content. We'd like to do this more declaratively, but we currently use IAddChild to get optimal runtime performance. The system can't do it for the Button, because elements are not forced to store text or child elements in any particular place.
Values in Attributes aren't as Powerful as XML can be
I might want to create a gradient instead of a solid color. While we could invent a syntax that works inside of the attribute syntax, this kind of thing is better described via our Compound Property syntax..
Is a Tag a Child Element or Compound Property Setting?
Since our Button sometimes want to have child elements:
<Button>
<Image … />
</Button>
We need a way to differentiate if a Tag inside of an element should create an object, or should it be treated as a "I'm about to set a value" tag.
We currently interpret any Tag with a period in it as a Compound Property tag. The example below shows that we can put arbitrary CLR objects (LinearGradientBrush) inside of a CompoundProperty tag. As long as the type is compatible with the property being set, it works.
Modifying digitalnetbizz's example into this Button, you'd get:
<Button Click="clickhandler">
Ok
<Button.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="red" Offset="0"/>
<GradientStop Color="yellow" Offset="1" />
<GradientStop Color="blue" Offset="0.5"/>
<GradientStop Color="white" Offset="0.2"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Button.Background>
</Button>
Avalon will do the following:
6) Create an instance of the System.Windows.Controls.Button class
7) Using the FromString capabilities of the Brush type converter to convert "Red" into a red brush object
8) Set the Background property of button instance to the red brush object
9) Add an event handler to the button's click event that calls the "clickhandler" routine that the user defines in C#/VB/or any language they choose.
10) Call IAddChild.AddText("Ok") on the Button. The Button is responsible for implementing this interface if it wants to handle text content. We'd like to do this more declaratively, but we currently use IAddChild to get optimal runtime performance. The system can't do it for the Button, because elements are not forced to store text or child elements in any particular place.
11) Create a LinearGradientBrush object
12) Create a GradientStopCollection object
13) Create 4 GradientStop objects, add them to the GradientStopCollection
14) Set the GradientStopCollection as the LinearGradientBrush's GradientStops property
15) Set the LinearGradientBrush as the Button's Background property
Naming History
We originally called this use of Tags to set Properties "Complex Properties".
Before the PDC, we decided to start calling them "Compound Properties", but not everybody got the message, so you may still see references to "Complex Properties".
Considering Changing the Syntax
We are debating whether we should change the syntax we use for Compound Propertis. Here are some of the choices that we are discussing:
1) <Class.PropertyName>: Keep what we have: <Button.Background>
a. Pros: it works today. It is consistent with our attached property syntax (DockPanel.Dock). Fairly writable
b. Cons: dots in tagnames are weird. Not as readable as <Attributes>
2) <Attributes>: Require all Compound Property settings to be grouped inside an <Attributes> tag.
<Button>
<Image … />
<Attributes>
<Background>
<LinearGradientBrush>
…
</LinearGradientBrush>
</Background>
</Attributes>
</Button>
a. Pros: Readability. It is more clear which child tags are element and which are compound property settings.
b. Cons: Syntax is much more verbose. Writability suffers! Creating a simple style now takes the following:
<DockPanel … >
<Attributes>
<Resources>
<Style>
<Button Background="Green" />
</Style>
</Resources>
</Attributes>
</DockPanel>
3) <_PropertyName>: Use a special character at the beginning of a tagname to denote that it is a property:
<Button>
<Image … />
<_Background>
<LinearGradientBrush>
…
</LinearGradientBrush>
</_Background>
</Button>
- Pros: Just as clear as <Class.PropertyName>.
- Cons: Not consistent with attached property syntax
4) First Check for Property then, object.
Often elements will have properties named identically to a type. We could choose to always assume that something is a property first, if it isn't found, then treat it as an object.
<Button>
<Image … />
<Background>
<LinearGradientBrush>
…
</LinearGradientBrush>
</Background>
</Button>
- Pros: understandable. Writable.
- Cons: you have to walk the parent chain to understand if a tag is an object or not. Compile time perf is slower, but runtime wouldn't need to be hurt since you can encode into baml whether it is a property or an object.
Final Naming
Once we finalize our choice here, we'll figure out what to call it...Compound Property may not be the best name.