Partager via


Dark Secrets of the WPF SDK Exposed!

* Introduction

Those of you that have been on the .NET journey since versions 1.0, 1.1, and 2.0 have probably noticed that there are a few things that are .... different about the .NET 3.0 documentation in the WPF area. In particular, WPF is responsible for having introduced a few broad new concepts into the documentation that are pushing the envelope for CLR and managed code. Some of the WPF SDK team's efforts to present these new concepts in reference material are very much works in progress, destined to change as other technologies also adopt same or similar paradigms in their public APIs.

* Am I the .Fairest of all? System.Reflection and the .NET 3.0 SDK

It's probably not a secret that the "magic" that Microsoft uses to create the framework of their managed SDKs is a reflection process (typically using managed reflection, but sometimes unmanaged reflection also, depending on the API set). Build tools reflect over the sum total of the .NET 3.0 APIs, and we SDK writers fill in the skeleton of what reflection told us about the API with great heaps of geek goodness (that's the goal at least!) However, one thing that System.Reflection does not do particularly well is reflecting against programming concepts that are newer than System.Reflection itself. You can get hints of what's underneath by interpreting custom attributes. But when it comes to something like the XAML language, or dependency properties, System.Reflection as shipped essentially unchanged since 1.1 does not provide nice clean APIs for discovery of 3.0 APIs. If you are writing your own reflection you have to do some extra discovery work (I won't describe that here, it's complex and out of the scope of this topic.) For our SDK's build team, they had to write on-top-of-Reflection code too. Then, various other people including some of us writers had to come up with presentation strategies for how the extra information could/should be presented amidst the more well-established and standard pieces of managed code documentation like Exceptions and Return Value et al.

The Dark Secrets in question are the sections in reference topics that are the results of lots of design meetings and lots of development work. Each Dark Secret represents a particular aspect of programming that is quite relevant to WPF, and new with WPF. The information is all there for you to discover, in the SDK pages. But, we have not been necessarily clear about just what these extra sections that suddenly showed up in the WPF reference are, and what they mean.

Well ... throw open those portals! Let light onto these Dark Secrets of WPF Documentation! All shall be explained!

* Dependency Properties

Many is the time that the question has been asked "just what is a dependency property anyways?" Or, a related and more pointed question: "Why do I care if something is a dependency property?" Our version of the answers: Dependency Properties Overview.

Once past that conceptual hurdle, a next logical question would be "OK, a dependency property is just a way of backing a CLR property, so how can I tell which properties are backed this way?"

And behold, we encounter Dark Secret Number One: dependency properties, and the Dependency Property Information section.

In the documentation, there are two ways to discover that a given property is a dependency property.

1) As you are browsing the members tables for any given type, and are looking at the public properties, read the description. If the property is a dependency property, then the last sentence in the description will read: "This is a dependency property."

I suppose that's not really much of a secret, is it? :-) Nevertheless, it's the kind of text that might be easy to skip over because of its frequency.

2) Suppose you've arrived on a topic page in the SDK that documents a CLR property. What now? Well, yet again, in the same description that got promoted into the members tables, you'll find the sentence "This is a dependency property."

Dependency Property Information

In addition to the descriptions, there is a section within the property page for each dependency property called appropriately enough the Dependency Property Information section. This section contains two items in a table:

* A link to the static field that holds the identifier for the dependency property. A fair number of property system APIs will require this identifier in order to act on a property or to get other information about it. That said, using the property system APIs isn't generally necessary for application programming that just gets or sets a particular existing property, because you can typically call the simpler CLR "wrappers" that are present on dependency properties. The identifier is thus mostly relevant for advanced programming tasks involving dependency properties, such as working with property metadata or tracing property values.

* If a property is a framework-level property, then the Dependency Property Information section lists which "flags" are set to true in the metadata. The flags report certain common characteristics of dependency properties as they are interpreted by the WPF framework level, particularly by subfeatures such as the layout system, data binding, or inheritance of property values. The SDK reports these flags because it is useful for instance to know whether changing a property forces a layout redraw, or whether you can omit specifying two-way state in a Binding because that's already the default for a particular dependency property.

Default Value

One concept that crosses over between dependency properties and 'regular' properties is default value. Generally, the .NET documentation gives you property default values in the Property Value section, and for consistency this is also where the default properties are reported for dependency properties. However, dependency property default value actually comes from property metadata, whereas in a "plain" CLR property it might come from a class ctor or a setter implementation. A dependency property can thus be easily changed by each subclass or new property owner, by overriding property metadata. This happens occasionally in the existing WPF dependency properties. When it does, the overrides by each class will be noted in the Remarks section.

* Routed Events

Before you ask the inevitable "what are routed events?" - here you go ... Routed Events Overview. Now that we have that out of the way ... :-)

Unlike dependency properties, routed events do not have a description convention of something like "this is a routed event". The base elements (UIElement, FrameworkElement, ContentElement, FrameworkContentElement) have lots of routed events; probably 75% of their events are routed. Other classes such as controls will have a smattering of routed events also, perhaps interspersed with standard CLR events that don't route. In order to tell whether an event routes or not, you need to look for the presence or absence of a Routed Event Information section in the event topic.

The Routed Event Information section is a table with three items:

* A link to the static field that holds the identifier for the routed event. As with the property system APIs and dependency property identifiers, event system APIs will require this identifier in order to access the event. Simple operations such as adding or removing handlers don't necessarily require the identifier, and again this is because the routed event will have a "wrapper" so that the intuitive CLR syntax for adding/removing event handlers in each CLR language is supported. But if you use AddHandler directly, or call RaiseEvent, you need to know the routed event's identifier.

* The routing strategy. There are three possibilities: Bubbling, Tunneling and Direct. Here's a little secret: if the event name has Preview in it, then routing strategy is always Tunneling, by convention. But telling Bubbling from Direct is a little harder because there's no differentiating naming convention. Therefore we provide that information in the reference page. Direct events don't actually route beyond the element that raises them, but they still serve a WPF-specific purpose, which is described in Routed Events Overview.

* The delegate type. You can also find that delegate listed in the declarative event syntax, but we repeat it here for convenience, so that you can get straight to the point of writing the appropriate handler.

* Attached Properties

Attached properties are strictly speaking a XAML concept, not a WPF concept. But WPF is the first published adopter of the XAML language, so WPF is also pioneering some documentation concepts for how to document XAML syntax and the XAML language. If you are a code programmer, and you have a look at the documentation for a given attached property, say DockPanel.Dock, you might notice something peculiar: there is only a XAML syntax there, no code syntax. You can verify that if you look at reflection or object browse the DockPanel class: there's no such thing as a "Dock" property to the CLR. To even make this page exist in the otherwise reflection-generated reference, the SDK build team had to inject this page. However, for the benefit of those of us who converse equally freely in markup or code, the syntax sections for attached properties do provide a link to the "real" code API for an attached property, which turns out to be a matched set of Get and Set accessor methods. For the DockPanel class these are GetDock and SetDock. (Sadly, these don't seem to be true links in the MSDN versions of these pages; it works in the Visual Studio and offline Windows SDKs... trust me ...)

* Attached Events

Similar drill for attached events. XAML concept, but with a WPF specific implementation. XAML syntax, but "secret" accessor methods for equivalent code access. In the attached events case, the pattern for these methods is Add*Handler and Remove*Handler. So, for instance, Mouse.MouseDown can have handlers attached on a given UIElement instance by calling AddMouseDownHandler, and removed by RemoveMouseDownHandler. For practical applications, attached events might not be that important, because most are re-exposed by UIElement in more convenient fashion. But attached events might come into your field of view if you are writing a suite of related controls, or implementing a service.

* XAML Syntax

The SDK documentation provides XAML syntax for various XAML usages, such as the object element tag you use to instantiate a class in XAML, attributes you use for setting properties or attaching event handlers, and XAML-specific concepts such as content property or property element syntax. Here comes another dark secret ... well, it's not so secret because I've blogged about it before. XAML is not necessarily bounded by a schema. The ultimate arbitrator of valid XAML is a XAML loader, and the ultimate pass-fail comes from loader actions such as trying to find a matching named type in an assembly, calling its default ctor, and returning an instance. Or, once that object exists, trying to find a property matching an attribute name and then trying to fill it either with a string-to-X conversion of the attribute value, or an even more complicated packaging of whatever XAML exists there in a child relationship for a property element. These degrees of freedom are necessary to keep the eXtensible X in XAML, but they can make documenting an ostensibly static XAML lexicon a bit more difficult. For one thing, the parser will happily allow you to instantiate an element that really has no "home" in an object model. For example, most EventArgs subclasses can be created in XAML, because they conventionally have a default ctor (it's that easy to join the XAML club, folks ... well, that and your assembly has to be either mapped, or prewired by a build target). But, then what? From a narrow definition, XAML is for UI definition. From a wider definition, XAML is for definition of any structure of related objects and their properties that you wish to construct. EventArgs really fits into neither of these definitions, and you cannot put an EventArgs element as a child of anything with dubious exception of a Resources collection. This leaves us XAML documenters in a quandary: is it XAML, or not? This quandary comes up frequently. Generally, we try to document XAML from a scenario standpoint. Is there any REASON why you might want this class instantiated in XAML? If so, we'll show you a syntax. If not, like for EventArgs subclasses in 3.0, we tell you it's not TYPICAL to use this class, even if a XAML loader would create one from XAML in total isolation from any application-oriented object model.

And another secret: there are lots of classes in the frameworks that are XAML capable even though there is no syntax shown (will say something like 'not applicable'). Generally this is because the class comes from an earlier version, and policing the entire pre 3.0 framework for possible legitimate XAML usages is pretty Herculean. So, you customers out there need to know some XAML tricks in order to fill in the blanks. For starters, read the topic XAML and Custom Classes. There's nothing different between a custom class and an existing class when it comes to satisfying a XAML loader with a default ctor and a few other qualifiers. And also have a look at the sample in x:Array Markup Extension. That sample maps the System namespace and mscorlib assemblies such that you can instantiate a String class as a direct object. You could extrapolate on that admittedly silly concept and map more useful things. It's a little hard to even envision the scenarios, but you're a creative bunch out there: show us what you can do! Map some System.Data structures? Who knows what hidden XAML usages lurk in the heart of the pre-3.0 .NET?

* No XAML Attributes lists?

The SDK does not really have a "property page" that is specific for XAML. You can see property listings as part of the general members tables, but it is a little harder to pick out the XAML attributes because some are read-only, some don't use XAML-supportable types, etc. In this area, I think we have to admit that tools and designers do a better job than a members table in the SDK can. That is because tools and designers have the advantage of context; they know specifically what Panel subclass you just instantiated, how it is contained in the element tree, etc. Getting good integration between tools-based Intellisense for the basic list of possibilities, and then being able to F1 for more information that comes from SDK pages, is a next level of sophistication we are really trying to pursue for upcoming tools/SDK releases. The story here is less than pleasing currently.

* No XAML XSD Schema?

I've blogged about that before. Schemas for XAML are hard for a product with as much dimension as WPF. But you might have noticed that the following generation of XAML incorporating technologies (Workflow Foundation, Silverlight) do include XSD type schemas. And for schemas in WPF XAML specifically ... stay tuned ...

Comments

  • Anonymous
    May 10, 2007
    As 2006 World Series hero Jeff Weaver completes his career self-immolation today in Detroit, let me recommend