Getting DependencyProperty RegisterAttached properties to appear in the Property Browser redux
I posted an earlier entry on this topic, but deleted it for this entry instead. I hope to clarify a few questions and correct some of the code as well (thanks Dharma and Akash).
Back again with another frequently asked question on our internal discussion alias (and a tester also opened a bug for a sample on how to do this).
This time, we're going to look at how activities can project their properties to their children through DependencyProperty.RegisterAttached and the work involved to have them show up in the Visual Studio property browser.
To see an example of this in WF, drag a Conditioned Activity Group on to the design surface and add a child activity (like a code activity). Notice that in addition to the child activity's properties (Execute Code), a "WhenCondition" has been added to the child. Fire up Lutz's reflector and you'll see that "WhenCondition" is a Dependency Property on the CAG.
We're going to use System.ComponentModel.IExtenderProvider to provide the logic of extending the activities properties to the children in the property browser. There numerous articles which talk about IExtenderProvider, but I thought it'd be useful to give an example within the context of WF.
There are three types we need to define: the activity, the implementation of IExtenderProvider and the activity designer which ties them both together.
Lets start by launching Visual Studio, creating a new Activity Library and defining a new dependency property. To expedite matters, use the workflow code snippets and change the "Register" method to "RegisterAttached".
For the purpose of this sample, the parent activity will project a property onto its children. Thus, the standard get/set methods which would define the property on the parent are not needed.
However, since the child activity inherits the properties from the parent (versus having the property defined directly) the parent needs to provide a way for the child to get/set values. Thus, we define two statics which accomplish the get/set semantics.
Now, lets create a new class which will implement IExtenderProvider. I'd recommend reading the article written by James Johnson to get up to speed, but I'll provide a coles notes version
- The IExtenderProvider interface only has one method, bool CanExtend(object). This method tells the designer whether the extended properties should be displayed for the given object. This interface has no information about the properties as the designer gets the properties by looking for the ProvideProperty attribute on the component implementing IExtenderProvider. This method should return true to have the designer use reflection to begin looking for the extended properties
- The ProvideProperty attribute specifies the property name as well as the type of objects it can be applied to
- Once you have the attribute added you need to write two public methods, these methods act as the Get/Set parts of a property and are named Get
and Set . The Get method takes in a type of the kind the ProvideProperty attribute defines and returns the data type of the property. The Set method takes two arguments, the first is of the type of specified in the ProvideProperty attribute, the second is of the same data type as the Get returns, this is the value the user wishes to set the property to
Following these notes you'll end up with a class which should look like this:
Finally, we need to create a designer for this activity. Activity designers define the visual representation and behavior of the activity, thus, we can tie together the ExtenderProvider and Activity class through the designer (remember to attribute your activity with [Designer(..)]). The logic to add the ExtenderProvider is defined within the Initialize method.
Now, we can test our work out by adding a Workflow Console Application to the solution. Drag the custom activity onto the design surface and drag a code shape into the custom activity.
As you'd expect, inspecting the Property Browser shows a "Child" property which appears on the Code activity.
To test that the GetChildProperty method works, define a handler for the Code Activity and try out the code below.
Here's the code for this sample..