IgorShare Thoughts and Ideas

Consulting and Training

Implementing attached Dependency Properties for Custom Activities (the correct way)

Posted by Igor Moochnick on 02/06/2008

I’ve spent a lot of hours trying to understand why the attached dependency properties are not working or working sporadically, why the designer is not serializing them to XOML or omitting them during the diagram rendering, and here is a result. It appears that if you do not defined the Getter and the Setter a certain way – the compiler will tell you nothing and you’ll get this weird sporadic behavior.

  In the code below notice the difference in the get/Set signatures between the working ones (lines 9 & 14) and sometimes working ones (lines 20 & 25). The following code is a minimal set of steps you should do in order to make your attached properties to appear on the Properties Grid during the design-time and provide correct serialization and deserialization to and from the Workflows.

Note: you’re welcome to download full working source code with the test/demo workflows.

[DesignerAttribute(typeof(ReplicatorChildDesigner), typeof(IDesigner))]
public partial class ReplicatorChild : SequenceActivity
{
    public static readonly DependencyProperty MemberDataProperty =
       DependencyProperty.RegisterAttached("MemberData", typeof(string), typeof(ReplicatorChild));

    // CORRECT SIGNATURES !!!
    public static object GetMemberData(object dependencyObject)
    {
        return ((DependencyObject)dependencyObject).GetValue(MemberDataProperty);
    }

    public static void SetMemberData(object dependencyObject, object value)
    {
        ((DependencyObject)dependencyObject).SetValue(MemberDataProperty, value);
    }

    /*  WRONG SIGNATURES !!!
    public static string GetMemberData(DependencyObject dependencyObject)
    {
        return (string)((DependencyObject)dependencyObject).GetValue(MemberDataProperty);
    }

    public static void SetMemberData(DependencyObject dependencyObject, string value)
    {
        ((DependencyObject)dependencyObject).SetValue(MemberDataProperty, value);
    }
    */

    protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
    {
        // ... Code is ommited for simplicity
    }
}

[ProvideProperty("MemberData", typeof(Activity))]
public class ReplicatorChildMemberDataExtenderProvider : IExtenderProvider
{
    public bool CanExtend(object extendee)
    {
        return (extendee is Activity) && (((Activity)extendee).Parent is ReplicatorChild);
    }

    public string GetMemberData(Activity activity)
    {
        string value = null;

        if (activity.Parent is ReplicatorChild)
            value = (string)activity.GetValue(ReplicatorChild.MemberDataProperty);

        return value;
    }

    public void SetMemberData(Activity activity, string value)
    {
        if (activity.Parent is ReplicatorChild)
            activity.SetValue(ReplicatorChild.MemberDataProperty, value);
    }
}

public class ReplicatorChildDesigner : SequentialActivityDesigner
{
    protected override void Initialize(Activity activity)
    {
        base.Initialize(activity);

        IExtenderListService extenderListService = (IExtenderListService)GetService(typeof(IExtenderListService));
        if (extenderListService != null)
        {
            bool foundExtender = false;
            foreach (IExtenderProvider extenderProvider in extenderListService.GetExtenderProviders())
            {
                if (extenderProvider.GetType() == typeof(ReplicatorChildMemberDataExtenderProvider))
                    foundExtender = true;
            }

            if (!foundExtender)
            {
                IExtenderProviderService extenderProviderService =
                    (IExtenderProviderService)GetService(typeof(IExtenderProviderService));
                if (extenderProviderService != null)
                    extenderProviderService.AddExtenderProvider(new ReplicatorChildMemberDataExtenderProvider());
            }
        }
    }
}

					
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: