ChrisAn's Blog Please read my disclaimer.

simplegeek

a.k.a. Chris Anderson

Trees and events and properties - oh my!

I had a meeting at work today where I was asked to explain a bit about Avalons multiple trees, events, property system, resources, styles, etc... I didn't quite get to all of it, but I thought I'd share some of my explanation here...

Pre-reading... The Avalon rearchitecture Part 1, Part 2, and Part 3.

Trees

Avalon has One Tree, right? Well, that was what I claimed in a previous post... Of course, by now you should know that I firmly believe in the saying that "facts obscure the truth". From the view of the Avalon rearchitecture we did go down to one tree, however reality is never that clean.

Avalon as a "visual tree". That tree is a tree of objects that derive from MSAvalon.Windows.Media.Visual. Visual can be conceptually thought of as a rendering surface. In fact there are several types of visuals (2d rendering, 3d rendering, video, etc.). The base element class - MSAvalon.Windows.UiElement - derives from Visual also. Thus, the "visual tree" is a tree of visuals, some of which are also elements.

<LowLevelDetail BoredomFactor="High">
The "visual tree" is actually not really the display tree. The managed visual objects are compiled (converted, rendered, whatever you want to call it) into a "composition tree". This is built up of unmanaged "comp node" objects that are what we use for low level rendering and animation. It is these comp nodes that can animate and render at display refresh speed (yes, that means updating 60Hz+). No user code (or managed code) ever makes it to the composition tree - this is critical to maintain glitch free video and animation (not because of the GC or anything... the design of the composition tree could be an entire post...)... Communication between the composition tree and the visual tree is done through two one way message pipelines - one inbound, one outbound.
</LowLevelDetail>

Within this visual tree we needed to splice in things like a <Bold> or <Paragraph> - which can't be simply represented as a single visual (imagine a bold or paragraph that splits multiple pages). To facilitate this, we created a notion of the "logical tree" - that is a parent pointer (and children) that are not associated always with the visual hierarchy, but can have non-visual nodes in the tree.

Events

Events come in three flavors - preview events, bubbling events, and simple events.

Preview events (like PreviewKeyDown) travel down the tree from the root to the target element. Imagine if you press the key "A" inside of a textbox. The window at the root of the tree will first get the PreviewKeyDown event, followed by each element that is a parent of the textbox, until eventually the preview event makes it to the textbox.

Bubbling events (like KeyDown) travel from the target up to the root element. Again, imagine the textbox and your press "A". In this case the textbox gets the KeyDown event first, followed by each of the parents of the textbox, until eventually the event makes it all the way to the window.

Simple events (like TextChanged) only are raised on the target element. Almost all the property changed events are simple events (also called "Direct only" events).

Events are dealt with in two stages - build route, and invoke. Build route basically traces the path from the target element to the root of the tree. Then, during invoke, each element in the route is invoked with the event - either starting at the begining of the route or the end. The route will include elements from both the logical and visual tree - thus, you can handle the TextBox PreviewKeyDown event in the Bold element that is wrapped around it!

Properties

The Avalon property system - called the dependency property system - was originally designed as a way for our engineers to reuse code. We found that all of our properties wanted to share a great deal of features; inheritence, styling, change notification, attached storage, data binding, validation, etc. We didn't want to duplicate all the implementation of this for every property, so we had to find a way to make this work consistently across the platform. In addition, we didn't want the consumers of these components to have to learn a new concept, so we knew that we needed to leverage the existing CLR property system.

Dependency properties are defined with a token - the DependencyProperty - that uniquely identifies the property and lets the definer specify the various services that they want associated with that property. The definer then implements a CLR accessor for easy use. Thus, when you say "button1.Backgorund = Brushes.Red;" the dependency property system is actually invoked, and allowed to provide the implementation of that property.

This is a much more abreviated version of the discussion, but probably long enough to bore you all...

01/20/2004 11:09 PM | #Longhorn

Content © 2003 Chris Anderson | Subscribe to my RSS feed.

Powered by BlogX