创建自定义的Activity

创建自定义的活动

activity是工作流的执行单元,是可以重用的,组合模型。
基本的activity是工作流的执行步骤,复合的activity可以包含其他activitity。基本的activity来自wwf而且这些activity可以从vs2005的工具箱中拖放来使用。
   软件开发人员可以开发出自己的activity而且也很出现在vs的工具箱中。activity是类。我们可以定义他的属性,事件和方法。
练习1:创建复合的activity
这个练习比较简单,简单说明一下就ok了。
创建一个顺序工作流控制台项目A,然后在同一个解决方案中添加一个工作流activity项目,在这个类库项目已经有个activity类。在设计视图上添加两个codea ctivity。在这个两个code活动中各自添加他们的事件。简单输出一个文字就好了。然后编译这个工作流activity类库项目。然后打开A项目中的workflow文件的设计视图。这个时候看工具箱里面会自动出现一个组件目录。里面就有我们的自定义的activity。把他拖放到workfolw中。然后直接运行这个项目就行了。这个时候的运行结果就是我们自定义的activity中的两个code活动输出内容。
   这就是最简单的复合活动。需要注意的是这个是在项目A中不要添加工作流activity类库的引用。如果添加引用的话还会报错。自定义的活动不能拖放到workflow设计视图上面去。

练习2:创建一个简单活动
也就是说这个活动是最基本的单位,不能在分割。但是练习1里面的自定义活动其实是由两个code活动组成的。
还是先建立一个
Sequential Workflow Console Application项目我们叫做A。然后建立 Workflow Activity Library项目我们叫B。
这个项目是要建立一个自定义的发送邮件的活动。
把activity.cs的名字变成
SendMailActivity.cs. 
在设计视图中点击中间区域上面的部位,然后看属性面板。点击基础类项。在弹出的面板这样设置:
System.Workflow.ComponentModel.和右边的Activity。点击ok
然后看代码,在构造函数下面插入代码段:选择workflow。然后选择 DependencyProperty - Property.
他就会插入一些代码。这些代码对外暴露的就是我们的自定义活动的属性。他有这些参数。

Name

Type

Description

Browseable

Boolean

Indicates whether this property appears in the Properties window.

Category

String

A user-defined category for the property.

Description

String

A description for the property.

DesignerSerializationVisibility

Visible, Hidden, or Content

Determines how and if properties will be serialized.

Visible (the default) – the property will be serialized normally.

Hidden – prevents property serialization

Content – used for collection properties. The collection object itself is not serialized, however the contents of the collection are.

If a developer chooses a collection type, this property will be set to Content. If a developer chooses a non-serializable type, this property will be set to Hidden.

ValidationVisibility

Optional, Required, or Hidden

Specifies how the property’s value is validated.

Optional (the default) – the property can accept null values.

Required – The property must be set to a non-null value and is checked to ensure that this is the case.

Hidden – There is no automatic validation of the property’s value.

If ValidationVisibility is set to ‘Required,’ when the component is reused, it will require the property to be configured via smart tags, obviating the need for a check in the activity’s Validator class. 



举个例子:
 public static DependencyProperty ToProperty = System.Workflow.ComponentModel.DependencyProperty.Register("To", typeof(string), typeof(Activity1));

        [Description("To Email Address")]//描述的内容
        [Category("EmailActivity")]//我们的写的目录分类。像外观,方法这样的分类
        [Browsable(true)]//是否在属性面板可以看到
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string To
        {
            get
            {
                return ((string)(base.GetValue(Activity1.ToProperty)));
            }
            set
            {
                base.SetValue(Activity1.ToProperty, value);
            }
        }
这段代码就使我们的自定义活动拥有了发送电邮的To属性,也是就给谁发送的属性.
就这样我们重复做4个。建立From,Subject,Body。这四个属性就构成了发送电邮的4个必须属性。

Name

Type

Description

Category

From

string

From Email Address

EmailActivity

Subject

string

Subject of Email

EmailActivity

Body

string

Body of Email

EmailActivity

然后编译一下这个项目。打开A项目后。打开workflow的设计视图页面,查看工具箱,就可以看到我们生成的这个自定义的活动sendEmail。把他拖放到我们的workflow中。然后在workflow中点击我们的sendemail活动查看属性,就可以在属性面板中看到我们定义的4个属性。他们都在EmailActivity目录下。
     重新看我们的类库项目B。这个活动已经有了外观但是还没有方法。我们就要添加方法了。
就是重写活动执行这个方法。在这个方法里面我们简单的输出To这个属性的内容。当然我们应该写发送邮件的内容。发送邮件的方法根据4个参数大家完全可以实现。这里就不实现了。只是告诉大家如果要实现发送邮件方法或者其他方法都可以在这个方法体里面实现

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)

{  Console.WriteLine(To);

 return ActivityExecutionStatus.Closed;

}

当然这个To的内容应该是在项目A的发送邮件活动的属性面板里面设置
编译一下这个项目就完成了。
附件练习3:对电邮参数添加验证。
   我们定义了4个参数。From,To,Subject,Body。其中From和To必须是电邮格式,不然的话应该是个错误。但是我们的练习2没有涉及这个参数验证我们不论输入什么东西都是正常的。
   活动验证是活动组件模型的一部分。这个组件模型关注下面几个方面:
  
  • Designer: This component defines the visual representation of the activity on the workflow and custom activity designers.
  • Code generator: This is an extensibility point to generate custom code for an activity in a workflow. InvokeWebService, which is an out-of-the-box activity has such an implementation.
  • Validator: This component enforces the activity semantics both at the design time and run time (only during dynamic update).
  • Toolbox item: Defines the custom behaviour of the toolbox item representing the activity in a design environment like Visual Studio.
  • Executor: This is a stateless component which implements the execution semantics of an activity. This component may not be defined for simple cases, where the Execute() method of the activity is overridden as it was the case in the previous exercise.
  • Serializer: Provides customized serialization behaviour if needed.
  • Deployer: This code is run when a workflow including the activity is deployed to a hosting environment.
在我们的类库项目B中添加一个普通类cs文件ParametersValidator .cs。他要继承ActivityValidator这个类
具体也没有起解释了。代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.ComponentModel.Compiler;
using System.Text.RegularExpressions;

namespace ActivityLibrary1
{
    class ParametersValidator : ActivityValidator
    {
        public override ValidationErrorCollection ValidateProperties(ValidationManager manager, object obj)
        {
            ValidationErrorCollection validationErrors = new ValidationErrorCollection(base.ValidateProperties(manager, obj));

            Activity1 sendMailActivityToBeValidated = obj as Activity1;

            if (sendMailActivityToBeValidated == null)
            {
                throw new InvalidOperationException("Parameter obj is not of type SendMailActivity");
            }

            if (!IsValidEmailAddress(sendMailActivityToBeValidated.To))
            {
                ValidationError CustomActivityValidationError =
                    new ValidationError(String.Format("\'{0}\' is an Invalid destination e-mail address", sendMailActivityToBeValidated.To), 1);

                validationErrors.Add(CustomActivityValidationError);
            }

            if (!IsValidEmailAddress(sendMailActivityToBeValidated.From))
            {
                ValidationError CustomActivityValidationError =
                    new ValidationError(String.Format("\'{0}\' is an Invalid source e-mail address", sendMailActivityToBeValidated.From), 1);

                validationErrors.Add(CustomActivityValidationError);
            }

            return validationErrors;
        }

        public Boolean IsValidEmailAddress(String address)
        {
            // must only proceed with validation if we have data   
            // to validate
            if (address == null || address.Length == 0)
                return true;

            Regex rx = new Regex(@"[^A-Za-z0-9@\-_.]", RegexOptions.Compiled);
            MatchCollection matches = rx.Matches(address);

            if (matches.Count > 0)
                return false;

            // Must have an '@' character
            int i = address.IndexOf('@');

            // Must be at least three chars after the @
            if (i <= 0 || i >= address.Length - 3)
                return false;

            // Must only be one '@' character
            if (address.IndexOf('@', i + 1) >= 0)
                return false;

            // Find the last . in the address
            int j = address.LastIndexOf('.');

            // The dot can't be before or immediately after the @ char
            if (j >= 0 && j <= i + 1)
                return false;

            return true;
        }


    }
}
然后查看活动类的代码,在类的声明前面 添加特性 [ActivityValidator(typeof(ParametersValidator))]
就可以了。
然后重新编译一下,如果输入错误的email格式,这个项目就会报错
附件练习4,添加一个活动设计器
添加一个普通cs类文件。
SendMailDesigner .cs 继承ActivityDesigner类。我们需要重写三个方法:Initalize, OnPaint, 和 OnLayoutSize
全部代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace ActivityLibrary1
{
    class SendMailDesigner : ActivityDesigner
    {
        Activity1 parentActivity;
        protected override void Initialize(Activity activity)
        {
            base.Initialize(activity);
            parentActivity = (Activity1)activity;
        }

        protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e)
        {
            return new Size(230, 100);
        }
        protected override void OnPaint(ActivityDesignerPaintEventArgs e)
        {
            Rectangle frameRect = new Rectangle(this.Location.X, this.Location.Y, this.Size.Width - 5, this.Size.Height - 5);
            Rectangle shadowRect = new Rectangle(frameRect.X + 5, frameRect.Y + 5, frameRect.Width, frameRect.Height);
            Rectangle pageRect = new Rectangle(frameRect.X + 4, frameRect.Y + 24, frameRect.Width - 8, frameRect.Height - 28);
            Rectangle titleRect = new Rectangle(frameRect.X + 15, frameRect.Y + 4, frameRect.Width / 2, 20);

            Brush frameBrush = new LinearGradientBrush(frameRect, Color.DarkBlue, Color.LightBlue, 45);

            e.Graphics.FillPath(Brushes.LightGray, RoundedRect(shadowRect));
            e.Graphics.FillPath(frameBrush, RoundedRect(frameRect));
            e.Graphics.FillPath(new LinearGradientBrush(pageRect, Color.White, Color.WhiteSmoke, 45), RoundedRect(pageRect));
            e.Graphics.DrawString(Activity.QualifiedName, new Font("Segoe UI", 9), Brushes.White, titleRect);
            frameRect.Inflate(20, 20);

            string textToDisplay = String.Format("To : \'{0}\'\r\nFrom : \'{1}\'\r\nSubject : \'{2}\'\r\n", parentActivity.To, parentActivity.From, parentActivity.Subject);
            e.Graphics.DrawString(String.Format(textToDisplay, parentActivity.Subject), new Font("Segoe UI", 8), Brushes.Black, pageRect.X, pageRect.Y + 15);
        }

        private GraphicsPath RoundedRect(Rectangle frame)
        {
            GraphicsPath path = new GraphicsPath();
            int radius = 7;
            int diameter = radius * 2;

            Rectangle arc = new Rectangle(frame.Left, frame.Top, diameter, diameter);

            path.AddArc(arc, 180, 90);

            arc.X = frame.Right - diameter;
            path.AddArc(arc, 270, 90);

            arc.Y = frame.Bottom - diameter;
            path.AddArc(arc, 0, 90);

            arc.X = frame.Left;
            path.AddArc(arc, 90, 90);

            path.CloseFigure();

            return path;
        }

    }
}
然后再次查看活动的类视图,在类声明前面添加特性
[Designer(typeof(SendMailDesigner), typeof(IDesigner))]
重写编译,然后在项目B中查看我们的自定义活动就会发现他的外观已经变化了


博客竟然不能上传附件,唉,无奈




本文使用Blog_Backup未注册版本导出,请到soft.pt42.com注册。

原文地址:https://www.cnblogs.com/zjypp/p/2319435.html