I've created Native Activity that looks like this:
public sealed class ConsoleColorScope : NativeActivity
{
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="ConsoleColorScope"/> class.
/// </summary>
public ConsoleColorScope()
{
this.Color = ConsoleColor.Gray;
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets Body.
/// </summary>
[DefaultValue(null)]
public Activity Body { get; set; }
/// <summary>
/// Gets or sets Color.
/// </summary>
public ConsoleColor Color { get; set; }
#endregion
#region Methods
/// <summary>
/// The execute.
/// </summary>
/// <param name="context">
/// The context.
/// </param>
protected override void Execute(NativeActivityContext context)
{
context.Properties.Add(ConsoleColorProperty.Name, new ConsoleColorProperty(this.Color));
if (this.Body != null)
{
context.ScheduleActivity(this.Body);
}
}
#endregion
/// <summary>
/// The console color property.
/// </summary>
private class ConsoleColorProperty : IExecutionProperty
{
#region Constants and Fields
/// <summary>
/// The name.
/// </summary>
public const string Name = "ConsoleColorProperty";
/// <summary>
/// The color.
/// </summary>
private readonly ConsoleColor color;
/// <summary>
/// The original.
/// </summary>
private ConsoleColor original;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="ConsoleColorProperty"/> class.
/// </summary>
/// <param name="color">
/// The color.
/// </param>
public ConsoleColorProperty(ConsoleColor color)
{
this.color = color;
}
#endregion
#region Explicit Interface Methods
/// <summary>
/// Cleanup the workflow thread.
/// </summary>
void IExecutionProperty.CleanupWorkflowThread()
{
Console.ForegroundColor = this.original;
}
/// <summary>
/// Setup the workflow thread.
/// </summary>
void IExecutionProperty.SetupWorkflowThread()
{
this.original = Console.ForegroundColor;
Console.ForegroundColor = this.color;
}
#endregion
}
}
This is class taken from the working sample:
http://code.msdn.microsoft.com/windowsdesktop/Windows-Workflow-c5649c23#content
However, when I open XAML file, I'm unable to see child activities within scope, as it is shown on the picture on the link above. All I can see is the names of the scopes.
I've created my own version of NativeActivity and I have same issue. Is there some procedure that I have to follow that would allow me to see body of NativeActivity in which I can drag and drop other activities (similar to Sequence activity) as it is shown on the demo description?
You'll need to create an Activity Designer project to go along with your custom activity which has a drop-zone (a WorkflowItemPresenter
control) for placing an activity to fill your custom activity's body property with. Then you can setup the plumbing to link your designer to an activity. The following illustrates the steps in detail.
In your solution, add a new Activity Designer project named like <Your Custom Activity Library>.Design
. The assembly must be named <Your Custom Activity Library>.Design.dll
, so that Visual Studio will use your activity designers for your custom activities. In the XAML for your designer, you'll utilize the WorkflowItemPresenter
to display a drop-zone that accepts an activity that users of your custom activity can use.
<sap:ActivityDesigner x:Class="Your_Custom_Activity_Library.Design.ConsoleColorScopeDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation">
<Grid>
<sap:WorkflowItemPresenter HintText="Drop an activity here!"
Item="{Binding Path=ModelItem.Body, Mode=TwoWay}"
MinWidth="300"
MinHeight="150" />
</Grid>
</sap:ActivityDesigner>
The ModelItem in the XAML represents your activity, and you can have your designer set any property in your activity with it. In the above sample, I'm setting up the WorkflowItemPresenter
to bind to your activity's Body
property.
Next, add a class called RegisterMetadata
(can be any name really) that implements the IRegisterMetadata
interface. Its implementation is very simple:
public class RegisterMetadata : IRegisterMetadata
{
/// <summary>
/// Registers all activity designer metadata.
/// </summary>
public static void RegisterAll()
{
// Attribute table builder for the metadata store.
AttributeTableBuilder builder = new AttributeTableBuilder();
// Register the designer for the custom activities.
builder.AddCustomAttributes(typeof(ConsoleColorScope), new DesignerAttribute(typeof(ConsoleColorScopeDesigner)));
// Add the attributes to the metadata store.
MetadataStore.AddAttributeTable(builder.CreateTable());
}
/// <summary>
/// Registers this instance.
/// </summary>
public void Register()
{
RegisterMetadata.RegisterAll();
}
}
The way Visual Studio loads your custom activity designers is by looking for assemblies named <Your Custom Activity Library>.Design.dll
, and then it looks for a public class that implements the IRegisterMetadata
interface.
You should now be able to drag and drop your custom activity to a workflow and it will have a drop-zone allowing you to specify the Body
activity.
You can get fancy with your designer, and expose friendly controls to allow a user to setup your custom activity. You could also create your own designers for the out-of-the-box activities provided in the .NET Framework.
Hope that helps.