If your custom activity/workflow has children then they will be locked and you would not be able to add/remove those when re-using the activity in other activities/workflows. That means that a custom activity writer can safely assume his/her activity would be used as it is without changers. On the other hand it also means that once you create your custom activity, you can not really change it through regular means at either design or run time.

 

Besides these “by design” constrains there are some issues around the locked activities that have not been completly resolved in WF v1.0:

1)      WF serializer doesn’t serialize dynamically updated instances with locked activities correctly (it assumes that the custom activity would initialize itself correctly and thus outputs just the top level activity into xoml).

2)      Once the instance has been initialized, you can not change it at design time. This means that if you open an instance of such activity in workflow view, you would not be able to add/delete activities in it as well as change any of the properties on the activity or any of it’s children. What it also means, when you open an activity tree from currently executing instance, you’d not be able to construct the changes visually without some workaround.

 

Lets first look into the second issue. If you create a new workflow control library project in VS and open up the workflow1.designer.cs file, you’d see that code inside InitializeComponent() is wrapped by two CanModifyActivities property sets:

 

private void InitializeComponent()

{

      this.CanModifyActivities = true;

      ...

      // add activities, set their properties, etc...

      ...

      this.CanModifyActivities = false;

}

 

The CanModifyActivities is a protected property defined on the CompositeActivity class. The workaround that I use in the Workflow manager is to set this property to true when I want to be able to modify the custom activity with locked children in the workflow view for applying the changes to the runtime instance as discussed in the part one of this post:

 

internal void UpdateCanModifyFlag(IList<Activity> activities)

{

      if (!AllowDynamicUpdates)

            return;

 

      List<Activity> processingActivities = new List<Activity>();

      foreach (Activity rootActivity in activities)

      {

            processingActivities.Add(rootActivity);

            CompositeActivity compositeActivity = rootActivity as CompositeActivity;

            if(compositeActivity != null)

                  processingActivities.AddRange(GetNestedActivities(compositeActivity));

      }

 

      foreach (Activity childActivity in processingActivities)

      {

            if (childActivity is CompositeActivity)

            {

                  //this will set the dynamic updates flag on the root activity

                  Type activityType = childActivity.GetType();

                  PropertyInfo readOnlyProperty = activityType.GetProperty("CanModifyActivities", BindingFlags.NonPublic | BindingFlags.Instance);

                  readOnlyProperty.SetValue(childActivity, true, null);

            }

      }

}

 

Not the nicest and fastest piece of code, but it works.

 

The first issue will be solved in the upcoming third part of the article, stay tuned!