WF Activities—Defining the Workflow Parameters
Defining the Workflow Parameters
To process an order, the workflow requires these two parameters:
-
AccountId: This identifies the account that is placing the order. -
SalesItemId: This identifies the product that is being ordered.
-
In a real application, you might include other parameters such as a quantity for the product being ordered. But since this workflow is only designed as a demonstration of the CodeActivity, these parameters should suffice.
Property Types
Parameters can be defined for a workflow (or custom activity) in two ways. You can implement a normal .NET class property, or you can use a dependency property. The property value for a dependency property is stored in a central repository, rather than being implemented as a normal instance variable in your class.
The primary advantage to dependency properties is that they allow binding of property values to instance data at runtime. For example, you can bind the input property of one activity to an output property of another. The actual property values resulting from the binding is determined at runtime. Dependency properties are required when you want to bind properties from one activity to another. However, if you are binding an activity property to a workflow property, the workflow property is not required to be a dependency property. In this case, a normal C# property on the workflow class works fine.
For this example, using dependency properties is not strictly a requirement. This workflow will work correctly without them. However, they are commonly used throughout workflow development, particularly when implementing custom activities. Using dependency properties is a skill that you will need sooner or later. For this reason, it’s a good idea to jump right in and start using them now.
Adding Dependency Properties
In order to support dependency properties, a class must derive from the base DependencyObject class. The root System.Workflow.ComponentModel.Activity class derives from DependencyObject, so all workflow and activity classes support dependency properties.
To implement a dependency property, you register the property with the dependency system using the DependencyProperty.Register static method. You then define a .NET property in the normal way with the get and set keywords. However, within the get and set sections of the property definition, you use the GetValue and SetValue methods of the base DependencyObject class to retrieve and set property values.
All of this is best illustrated with a real example. To define the AccountId property for this workflow as a dependency property, you add this code to the Workflow1.cs file:
public static DependencyProperty AccountIdProperty = System.Workflow.ComponentModel.DependencyProperty.Register( "AccountId", typeof(Int32), typeof(Workflow1)); /// <summary> /// Identifies the account /// </summary> [Description("Identifies the account")] [Category("CodeActivity Example")] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Int32 AccountId { get { return ((Int32)(base.GetValue(Workflow1.AccountIdProperty))); } set { base.SetValue(Workflow1.AccountIdProperty, value); } }
By convention, the name of the static DependencyProperty returned by the Register method takes the form of MyValueProperty. MyValue is replaced with your property name. Following that convention, the property defined in the previous code for AccountId defines a static DependencyProperty named AccountIdProperty. This static field doesn’t contain the value of the property. Instead, it defines the dependency property that is registered with the dependency system.
As shown in the previous code, the get and set sections of the property call the GetValue or SetValue methods to retrieve or update the property value. The property values are stored in a repository that is keyed by the static DependencyProperty field. This is the field that is returned by the Register method. The repository acts like a Dictionary object that holds the current values of each property based on a unique key.
This may seem like a lot of code just to define a property, but it is necessary in order to take advantage of the activity binding features of WF. You’ll find that all dependency properties are defined in exactly the same way. Once you’ve implemented one property, the others are simply a matter of cutting and pasting.
To help with the drudgery of adding a dependency property, WF includes a Visual Studio code snippet for dependency properties. To use this, right-click the location in your source code where you want to add the property and select Insert Snippet. Then select Workflow, then DependencyProperty – Property. A dependency property with the appropriate boilerplate code is added.
Caution Windows Presentation Foundation (WPF) is another one of the foundations included with .NET 3.0. It also uses the concept of dependency properties and dependency objects. However, be aware that even though the class names are the same, they are not the same class. The DependencyObject and DependencyProperty used by WF are found in the System.Workflow.ComponentModel namespace. The WPF classes with the same names are found in the System.Windows namespace. They are not interchangeable. Perhaps sometime in the distant future, Microsoft will see fit to merge these classes into a common technology foundation that is shared by WPF and WF. Until then, be careful if you are developing an application that uses both foundations.
In addition to the AccountId property defined previously, the workflow also requires a dependency property named SalesItemId that is implemented in the same way. It is also an Int32.
The workflow also needs several local instance variables that will be used to store workflow state between activity steps. As activities are added to the workflow, you will see how these variables are used. Since these variables are only used locally within the workflow, they don’t need to be exposed as properties. They are defined like this:
private Boolean isAccountVerified; private Boolean isSalesItemVerified; private Decimal availableCredit; private Decimal salesItemAmount;
After adding the variables and dependency properties, the Workflow1.cs file should look like Listing 3-1.
Listing 3-1. Workflow1.cs File with Properties and Variables
using System; using System.ComponentModel; using System.Workflow.ComponentModel; using System.Workflow.Activities; namespace OrderEntryCode { /// <summary> /// Order entry workflow using CodeActivity /// </summary> public sealed partial class Workflow1 : SequentialWorkflowActivity { private Boolean isAccountVerified; private Boolean isSalesItemVerified; private Decimal availableCredit; private Decimal salesItemAmount; public Workflow1() { InitializeComponent(); } #region Public workflow properties public static DependencyProperty AccountIdProperty = System.Workflow.ComponentModel.DependencyProperty.Register( "AccountId", typeof(Int32), typeof(Workflow1)); /// <summary> /// Identifies the account /// </summary> [Description("Identifies the account")] [Category("CodeActivity Example")] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Int32 AccountId { get { return ((Int32)(base.GetValue(Workflow1.AccountIdProperty))); } set { base.SetValue(Workflow1.AccountIdProperty, value); } } public static DependencyProperty SalesItemIdProperty = System.Workflow.ComponentModel.DependencyProperty.Register( "SalesItemId", typeof(Int32), typeof(Workflow1)); /// <summary> /// Identifies the item to sell /// </summary> [Description("Identifies the item to sell")] [Category("CodeActivity Example")] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Int32 SalesItemId { get { return ((Int32)(base.GetValue(Workflow1.SalesItemIdProperty))); } set { base.SetValue(Workflow1.SalesItemIdProperty, value); } } #endregion } }
|

