Welcome to Windows Workflow Foundation (WF)
Top Tasks :

WF Team Bloggers

Browse by Tags

All Tags » Custom Activity   (RSS)

  • Are you getting a "The root activity type is invalid" error with the Custom Activity Designer sample?

    Several peolple have gotten a "The root activity type is invalid" error when using the Custom Activity Designer sample that can be found at http://wf.netfx3.com/files/folders/activity_behavior/entry840.aspx . I created an update project that should resolve the problem, which can be downloaded from the link below. Read More...
  • How to use custom ActivityCondition or filter which ActivityConditions are available

    If you have your own custom ActivityCondition you are only going to be able to use it with your custom activities, not out of the box activities like While or IfElseBranch. First start by creating your custom ActivityCondition like the following: [ DisplayName ( "Custom Activity Condition" )] public class CustomActivityCondition : ActivityCondition { public override bool Evaluate( Activity activity, IServiceProvider provider) { return ( this .customCondition.Equals( "foo" , StringComparison .CurrentCultureIgnoreCase)); } private string customCondition = string .Empty; public string CustomCondition { get { return this .customCondition; } set { this .customCondition = value ; } } } Next create a custom TypeConverter that will add your activity condition to the list of available activity conditions for your user to select like below: public class CustomActivityConditionTypeConverter : TypeConverter { private Hashtable conditionDecls = new Hashtable (); public CustomActivityConditionTypeConverter() { AddTypeToHashTable( typeof ( RuleConditionReference )); AddTypeToHashTable( typeof ( CodeCondition )); AddTypeToHashTable( typeof ( CustomActivityCondition )); } private void AddTypeToHashTable( Type typeToAdd) { string key = typeToAdd.FullName; object [] attributes = typeToAdd.GetCustomAttributes( typeof ( DisplayNameAttribute ), false ); if (attributes != null && attributes.Length > 0 && attributes[0] is DisplayNameAttribute ) key = (( DisplayNameAttribute )attributes[0]).DisplayName; Read More...
  • Windows workflow foundation animated activity designer source

    As I mentioned in my last post, I have uploaded the Animated Activity Designer for use in your own project. A common question I can anticipate being asked is "Why?". So, here's why I created it and my reason as to why you may want to use something like this.

    First off, the reason I wanted to try to created animated activities within the Windows Workflow designer was merely to see if it was possible. I knew that I could override OnPaint so I pretty much already knew it was going to be possible (otherwise I probably wouldn't have gone down the path). The second reason is simply because as a guy that loves cool eye candy in UI's, I just had to do it.

    So why would you ever want to create an animated activity? Let's say you create an application that hosts the Windows Workflow Designer. Let's also assume that this application is used by your customers. You present them with the designer surface and within a Toolbox like panel, you have your set of custom activities they can use. If pictures are worth a thousand words, then an animation with 10 frames is worth 10,000 words.

    The actual code for this is really simple which is also why it only took a couple of hours to get it up and running. Since it is so easy, I won't waste your time explaining it (but feel free to ping me if you have any questions).

    Download the code right here: AnimatedActivityDesigner.zip

    To see it in action, open the solution in Visual Studio, build it and then open workflow1.cs in the designer.

    Enjoy!

     To see the video better, right click and select Zoom -> Full Screen

    P.S. The activities you see in the project and in the video are simply placeholders. They do not actually do anything.

  • Switch activity

    The Switch activity I created is based on the switch statement in C# or the Select Case statements in VB . You have an expression and one or more case statements, one of which can be the default. To model within workflow the case becomes a property that must be on the children of the Switch activity, which you can do this a couple of ways. One would be to have a Case activity with a Cases property that would be a required child. Another would be to have an attached Cases property that would be added to all children of the Switch. I chose to use an attached property because I think it gives a better user experience and it makes for a better sample since I don’t think there are that many out there for advance attached property scenarios. When you use have an attached property it will not be displayed in the property browser until you create an IExtenderProvider and implement the CanExtend method like the following: bool IExtenderProvider .CanExtend( object extendee) { return (extendee is Activity ) && ((( Activity )extendee).Parent is Switch ); } Along with the CanExtend method you also need to implement methods used for getting and setting the value of the property. The naming convention that must be followed is the “Get” / “Set” followed by the name of the property. For the switch activity I have the following: [ TypeConverter ( typeof ( ActivityBindTypeConverter ))] [ CategoryAttribute ( "Switch" ), ] [ DescriptionAttribute ( "If any of the values in Cases equals the Read More...
  • Basics of Working with Custom Types in Workflow

    If you have used a custom type for an activity / workflow property you have probably ran into a few issues. You might have had problems trying to get it serialized correctly or to be able to set the value in the property browser. With this post I will try and shed some light on some of the basics. I will be working with the following custom type: [ Serializable ()] public class MyType { string paramOne; string paramTwo; public MyType( string paramOne, string paramTwo) { ParamOne = paramOne; ParamTwo = paramTwo; } public string ParamOne { get { return paramOne; } set { paramOne = value ; } } public string ParamTwo { get { return paramTwo; } set { paramTwo = value ; } } } The default workflow serialization works pretty good for types that have a default constructor. However, if your type is like the one above, which doesn’t, you aren’t going to get what you expect is you use the activity in a code only workflow. If the property has a default value other than null in the designer.cs file you will see something like the following: this .activity11.MyTypeProperty = (( MyType )(resources.GetObject( "activity11.MyTypeProperty" ))); And if you are using code separation it will look like the following: < ns0:Activity1 x:Name = " activity11 " > < ns0:Activity1.MyTypeProperty > < ns0:MyType ParamTwo = "" ParamOne = "" /> </ ns0:Activity1.MyTypeProperty > </ ns0:Activity1 > The code separation version looks good, but when you do anything that causes deserialization, Read More...
  • Do you want to invoke another workflow but you won't know which one until runtime?

    The InvokeWorkflowActivity that ships with WF requires you to set the type of the target workflow at design time. If you won’t know which workflow to invoke until runtime you need to write a custom activity. To invoke a workflow need to use the IStartWorkflow service that you can get from the ActivityExecutionContext , like the following: IStartWorkflow startWorkflow = executionContext.GetService( typeof ( IStartWorkflow )) as IStartWorkflow ; Guid instanceId = startWorkflow.StartWorkflow( this .TargetWorkflow, this .Parameters); Since the parameters won’t be known until runtime you can’t use the WorkflowParameterBindingsCollection because you wouldn’t be able to change in at runtime. Instead I have have a parameters property that is type Dictionary < string , object >. Read More...
  • Do you need to launch another process from your workflow?

    When start another process from your workflow you can’t just not return from the Execute method until the process completes. This would block the entire workflow from receiving any other events and would hold onto the thread. Instead you need to use a queue to get notification when the process completes. Read More...
  • How to set activity property from a custom input form

    Sometime you might want to create an input form for your user to set properties on your custom activity. Unfortunately when you set the properties directly on the activity from the input form the values don’t always get reflected on your activity. To resolve this you need to set the value on the PropertyDescriptor for the property instead, like the following: PropertyDescriptor firstPropDescr = TypeDescriptor .GetProperties( this .activity)[ "FirstName" ]; firstPropDescr.SetValue( this .activity, txtFirstName.Text); Below is a link to a sample employee activity that when you double click in it a input form pops up to enter the first and last name. Clicking the OK button sets the values on the activity. Read More...
  • Couple of custom activities that you can use to synchronize branches of a ParallelActivity

    You could use a SynchronizationScope Activity, but this would block execution all together in the other branches since the thread is locked until the activity is done executing. If that is not the behavior you are looking for here are two options. First, WaitFor, will block the branch that it is in until a selected activity in another branch is Closed or Executing. With this activity in the execute method you find out the execution status for the activity you are waiting for and if it is not status you subscribe for the StatusChanged event. Once the activity changes to the correct status the WaitFor is closed and the next child in that branch will execute. protected override ActivityExecutionStatus Execute( ActivityExecutionContext context) { ActivityExecutionStatus status; Activity activity = GetExecutableActivity( this .Activity); switch (activity.ExecutionStatus) { case ActivityExecutionStatus .Executing: if ( this .Status == "Closed" ) { activity.StatusChanged += this .OnStatusChangeHandler; status = ActivityExecutionStatus .Executing; } else { status = ActivityExecutionStatus .Closed; } break ; case ActivityExecutionStatus .Closed: status = ActivityExecutionStatus .Closed; break ; default : activity.StatusChanged += this .OnStatusChangeHandler; status = ActivityExecutionStatus .Executing; break ; } return status; } The other, SynchronizeActivity, you put one or more, must be equal, in each branch. When the activity executes is checks the other synchronize activities at the Read More...
  • Have you had problems using the FileWatcher sample in a StateMachineWorkflow or WhileActivity?

    If you have tried to use the FileWatcherActivity in either a WhileActivity or a StateMachineWorkflow you have probably not had much luck. The changes need to be made to the base activity InputActivity. To get it working in a while activity you need the following change to the ProcessQueueItem method: From: WorkflowQueue queue = qService.GetWorkflowQueue( this .QueueName); if (queue.Count == 0) { return false ; } To: WorkflowQueue queue = null ; if (qService.Exists( this .QueueName)) { queue = qService.GetWorkflowQueue( this .QueueName); } if (queue == null || queue.Count == 0) { return false ; } Now you you won’t get the following exception after the first file is added to the location the while is subscribed to: An exception of type 'System.InvalidOperationException' occurred in System.Workflow.Runtime.dll but was not handled in user code Additional information: Event Queue operation failed with MessageQueueErrorCode QueueNotFound for queue 'Event1'. With the state machine you get the same error but it is in a different place. This time it is in the Unsubscribe method. To resolve that problem you just need to check to make sure the queue exists before making a call to GetWorkflowQueues like the following: WorkflowQueuingService qService = context.GetService< WorkflowQueuingService >(); if (!qService.Exists( this .QueueName)) { return ; } WorkflowQueue queue = qService.GetWorkflowQueue( this .QueueName); I have updated the sample with the above changes and made a few other Read More...

Copyright © 2006 Microsoft Corporation. All Rights Reserved. | Terms of Use | Privacy Statement | Contact Us