WWF3自定义活动<第八篇>
WWF提供了对原有活动进行扩展以及自定义新活动的功能,用户可以通过"Workflow Activity Library"创建和开发自定义活动。
一、自定义活动类型
默认情况下,创建的自定义活动是继承"System.Workflow.Activities.SequenceActivity"父类的。该类型自定义活动的外观是由一个Sequence顺序类型的容器构成的,用户可以在Sequence活动内添加其他子活动。
属性如下:
代码如下:
namespace ActivityLibrary1
{
public partial class Activity1: SequenceActivity
{
public Activity1()
{
InitializeComponent();
}
}
}
活动的自定义方式:
继承的类型 | 说明 |
System.Workflow.Activities.SequenceActivity | 自定义顺序类型 |
System.Workflow.ComponentModel.CompositeActivity | 自定义补偿类型的自定义活动 |
System.Workflow.Activities.CallExternalMethodActivity | 在CallExternalMethod活动基础上封装一些额外的功能 |
System.Workflow.Activities.HandleExternalEventActivity | 在HandleExternalEvent活动基础上封装一些额外的功能 |
System.Workflow.ComponentModel.Activity | 自定义"ComponentModelActivity"类型的活动 |
如自定义补偿类型活动:
public partial class Activity1 : CompositeActivity
{
public Activity1()
{
InitializeComponent();
}
}
利用WWF开发出来的自定义活动使用起来也非常简单,在同一个解决方案下开发的自定义活动,只要编译成功后就可以在"工具栏"中看到并可以直接使用。
二、自定义普通属性
在WWF中可以通过"DependencyProperty"来存储和管理自定义活动的属性。
首先定义一个"DependencyProperty"属性并且利用它的"Register"方法进行注册。在注册时需要指明该"Dependency Property"属性所存储的"属性名称"、"属性的类型"、以及该属性"所在自定义活动的名称",还可以利用"PropertyMetadata"来为属性定义默认值。
namespace ActivityLibrary1
{
public partial class Activity1 : System.Workflow.ComponentModel.Activity
{
//将自定义活动"CustomActivity"中的一个字符类型属性"Paral"注册到"DependencyProperty"类型的属性"ParalProperty"中
public static DependencyProperty ParalProperty = DependencyProperty.Register("Paral", typeof(System.String), typeof(Activity1));
public string Paral
{
get
{
return ((string)(base.GetValue(Activity1.ParalProperty)));
}
set
{
base.SetValue(Activity1.ParalProperty, value);
}
} public Activity1()
{
InitializeComponent();
}
}
}
新建一个顺序工作流项目,可以看到工具箱多了选项,拖入工作流后还有一个叫Paral的属性。
自定义活动的特性:
特性名称 | 说明 |
DescriptionAttribute | 提示信息[Description("打印一个字符串!")] |
BrowsableAttribute | 是否在属性窗口显示[Browsable(true)] |
当然,用户可以通过"DependencyProperty"属性的"PropertyMetadata"方法来为其设置默认值。
public static DependencyProperty ParalProperty = DependencyProperty.Register("Paral", typeof(System.String), typeof(Activity1),new PropertyMetadata("默认赋的值!"));
从新编译后,可以看到刚刚拖入进来的控件已经有了默认值。
三、自定义事件类型属性
除了上面提到的普通属性外,还有一种事件属性。用户可以通过该属性创建相应的事件。例如Code活动的"ExecuteCode"属性就能够用来创建一个事件,开发人员可以在该事件中执行相应的业务操作。事件属性的创建与前面类似,只是属性类型是"event"类型。
自定义一个活动如下:
namespace ActivityLibrary1
{
[ToolboxItemAttribute(typeof(ActivityToolboxItem))]
public partial class Activity1 : System.Workflow.ComponentModel.Activity
{
//将自定义活动"CustomActivity"中的一个字符类型属性"Paral"注册到"DependencyProperty"类型的属性"ParalProperty"中
public static DependencyProperty PrintEvent = DependencyProperty.Register("Print", typeof(EventHandler), typeof(Activity1));
public event EventHandler Print
{
add
{
base.AddHandler(PrintEvent, value);
}
remove
{
base.RemoveHandler(PrintEvent, value);
}
}
//用户必须重载父类的"Execute"方法,并通过"RaiseEvent"来加载相应"DependencyProperty"属性,该属性才能执行
protected override ActivityExecutionStatus Execute(ActivityExecutionContext context)
{
base.RaiseEvent(PrintEvent, this, EventArgs.Empty);
return ActivityExecutionStatus.Closed;
} public Activity1()
{
InitializeComponent();
}
}
}
新建一个工作流,拉入控件后,显示如下:
四、自定义活动的验证方式
在使用WWF进行工作流设计时,如果某些属性没有设置或设置错误,那么WWF将会给出相应的提示,在进行自定义活动时同样可以实现对属性值进行验证的功能。
首先建立一个专门用于对属性值进行验证的类,然后继承自"System.Workflow.ComponentModel.Compiler.ActivityValidatoe",并重载"ValidationErrorCollection"方法。
在该方法中用户可以对所需要验证的属性进行逐一判断,如果验证失败,则可以通过ValidationError错误将属性收集,最后一起返回给用户。
下面给出一个验证属性的示例:
namespace ActivityLibrary1
{
[ActivityValidator(typeof(CustomActivityValidator))]
public partial class Activity1 : System.Workflow.ComponentModel.Activity
{
//将自定义活动"CustomActivity"中的一个字符类型属性"Paral"注册到"DependencyProperty"类型的属性"ParalProperty"中
public static DependencyProperty ParalProperty = DependencyProperty.Register("Paral", typeof(System.String), typeof(Activity1), new PropertyMetadata("你好!"));
public string Paral
{
get
{
return ((string)(base.GetValue(Activity1.ParalProperty)));
}
set
{
base.SetValue(Activity1.ParalProperty, value);
}
} public Activity1()
{
InitializeComponent();
}
} //创建一个类,继承自ActivityValidator
public class CustomActivityValidator : System.Workflow.ComponentModel.Compiler.ActivityValidator
{
//重写ValidationErrorCollection方法
public override ValidationErrorCollection ValidateProperties(ValidationManager manager, object obj)
{
ValidationErrorCollection validationErrors = base.ValidateProperties(manager, obj); Activity1 activity = obj as Activity1; if (activity != null)
{
//当属性为空时,添加到validationErrors
if (String.IsNullOrEmpty(activity.Paral))
{
validationErrors.Add(ValidationError.GetNotSetValidationError(Activity1.ParalProperty.Name));
}
//当属性不包含感叹号时,添加到validationErrors
else if (!activity.Paral.Contains("!"))
{
validationErrors.Add(new ValidationError("没有包含感叹号啊,大哥!", , false, Activity1.ParalProperty.Name));
}
}
return validationErrors;
}
}
}
当我们新建一个工作流,再使用这个控件,但是属性值不包含感叹号时。生成报如下错误:
五、自定义活动的外观
对于自定义的活动,WWF支持自定义活动的图标,只需将一个图片加载到自定义活动的项目中,然后将该图片的属性"Build Action"设置为"Embedded Resource"(生成操作设为嵌入的资源)。最后在自定义活动类的上面添加以下标识。
namespace ActivityLibrary1
{
[ToolboxBitmap(typeof(Activity1), "pic.1.bmp")] //设置自定义图标
[Designer(typeof(CusActivityDesigner), typeof(IDesigner))] //设置自定义样式
public partial class Activity1 : System.Workflow.ComponentModel.Activity
{
public Activity1()
{
InitializeComponent();
}
}
//自定义样式类
public class CustomTheme : ActivityDesignerTheme
{
public CustomTheme(WorkflowTheme theme) : base(theme)
{
this.BorderColor = Color.Red; //边框红色
this.BackColorStart = Color.White; //渐变从白色开始
this.BackColorEnd = Color.Blue; //渐变从蓝色结束
}
} [ActivityDesignerThemeAttribute(typeof(CustomTheme))]
public class CusActivityDesigner : ActivityDesigner
{
}
}
工作流显示效果如下:
六、综合示例
模拟一个计算器,然后将其中的计算功能作为一个自定义活动进行开发,然后在工作流中进行使用。
1、创建自定义活动
namespace ActivityLibrary1
{
[ActivityValidator(typeof(CustomActivityValidator))]
public partial class CustomActivity : System.Workflow.ComponentModel.Activity
{
public static DependencyProperty Para1Property = DependencyProperty.Register("Para1", typeof(System.Int32), typeof(CustomActivity), new PropertyMetadata());
public static DependencyProperty Para2Property = DependencyProperty.Register("Para2", typeof(System.Int32), typeof(CustomActivity), new PropertyMetadata());
public static DependencyProperty OperProperty = DependencyProperty.Register("Oper", typeof(System.String), typeof(CustomActivity), new PropertyMetadata("+")); public static DependencyProperty InvokedEvent = DependencyProperty.Register("Invoked", typeof(EventHandler<CustomActivityEventArgs>), typeof(CustomActivity)); public CustomActivity()
{
InitializeComponent();
} [DescriptionAttribute("运算符")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string Oper
{
get
{
return ((string)(base.GetValue(CustomActivity.OperProperty)));
}
set
{
base.SetValue(CustomActivity.OperProperty, value);
}
} [DescriptionAttribute("整型数字")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int Para1
{
get
{
return ((int)(base.GetValue(CustomActivity.Para1Property)));
}
set
{
base.SetValue(CustomActivity.Para1Property, value);
}
} [DescriptionAttribute("整型数字")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int Para2
{
get
{
return ((int)(base.GetValue(CustomActivity.Para2Property)));
}
set
{
base.SetValue(CustomActivity.Para2Property, value);
}
} [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
[Category("Handlers")]
public event EventHandler<CustomActivityEventArgs> Invoked
{
add
{
base.AddHandler(CustomActivity.InvokedEvent, value);
}
remove
{
base.RemoveHandler(CustomActivity.InvokedEvent, value);
}
} protected override ActivityExecutionStatus Execute(ActivityExecutionContext context)
{
CustomActivityEventArgs e = new CustomActivityEventArgs(); if (Oper == "+")
e.Result = (this.Para1 + this.Para2).ToString();
else if (Oper == "-")
e.Result = (this.Para1 - this.Para2).ToString();
else if (Oper == "*")
e.Result = (this.Para1 * this.Para2).ToString();
else if (Oper == "/")
e.Result = (this.Para1 / this.Para2).ToString(); this.RaiseGenericEvent<CustomActivityEventArgs>(InvokedEvent, this, e); return ActivityExecutionStatus.Closed;
}
} public class CustomActivityEventArgs : EventArgs
{
private string result; public string Result
{
get { return result; }
set { result = value; }
}
} public class CustomActivityValidator : System.Workflow.ComponentModel.Compiler.ActivityValidator
{
public override ValidationErrorCollection ValidateProperties(ValidationManager manager, object obj)
{
ValidationErrorCollection validationErrors = base.ValidateProperties(manager, obj); CustomActivity activity = obj as CustomActivity; if (activity != null)
{
if (String.IsNullOrEmpty(activity.Oper))
{
validationErrors.Add(ValidationError.GetNotSetValidationError(CustomActivity.OperProperty.Name)); }
if (activity.Para2 == )
{
validationErrors.Add(new ValidationError("除数不能为0", , false, CustomActivity.Para2Property.Name));
}
}
return validationErrors;
}
}
}
2、新建一个工作流,里面就一个自定义活动
代码如下:
namespace WorkflowConsoleApplication1
{
public sealed partial class Workflow1 : SequentialWorkflowActivity
{
private string oper;
public string Oper
{
get { return oper; }
set { oper = value; }
}
private int para1;
public int Para1
{
get { return para1; }
set { para1 = value; }
}
private int para2;
public int Para2
{
get { return para2; }
set { para2 = value; }
}
public Workflow1()
{
InitializeComponent();
}
private void Invoked(object sender, ActivityLibrary1.CustomActivityEventArgs e)
{
MessageBox.Show(e.Result);
}
}
}
注意要设置好这些属性,否则可能运行不成功:
全部绑定到自定义控件的对应属性。
3、新建一个Winform项目
界面如下:
代码如下:
public partial class Form1 : Form
{
private WorkflowRuntime wfRuntime = null;
private WorkflowInstance wfInstance = null; public Form1()
{
InitializeComponent(); wfRuntime = new WorkflowRuntime();
wfRuntime.StartRuntime();
} private void button1_Click(object sender, EventArgs e)
{ Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("Oper", this.comboBox1.Text);
parameters.Add("Para1", Convert.ToInt32(this.textBox1.Text));
parameters.Add("Para2", Convert.ToInt32(this.textBox2.Text)); wfInstance = wfRuntime.CreateWorkflow(typeof(CustomActivity.Workflow1),parameters); wfInstance.Start();
}
}
效果如下:
WWF3自定义活动<第八篇>的更多相关文章
- Python之路【第十八篇】:Web框架们
Python之路[第十八篇]:Web框架们 Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Pytho ...
- 第八篇 :微信公众平台开发实战Java版之如何网页授权获取用户基本信息
第一部分:微信授权获取基本信息的介绍 我们首先来看看官方的文档怎么说: 如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑. 关于网页授权回调域 ...
- 第八篇 Replication:合并复制-How it works
本篇文章是SQL Server Replication系列的第八篇,详细内容请参考原文. 在这一系列的前几篇你已经学习了如何在多服务器环境中配置合并复制.这一篇将介绍合并代理并解释它在复制过程中扮演的 ...
- 第八篇 SQL Server代理使用外部程序
本篇文章是SQL Server代理系列的第八篇,详细内容请参考原文 在这一系列的上一篇,学习了如何用SQL Server代理作业活动监视器监控作业活动和查看作业历史记录.在实时监控和管理SQL Ser ...
- 【译】第八篇 Replication:合并复制-How it works
本篇文章是SQL Server Replication系列的第八篇,详细内容请参考原文. 在这一系列的前几篇你已经学习了如何在多服务器环境中配置合并复制.这一篇将介绍合并代理并解释它在复制过程中扮演的 ...
- 【译】第八篇 SQL Server代理使用外部程序
本篇文章是SQL Server代理系列的第八篇,详细内容请参考原文 在这一系列的上一篇,学习了如何用SQL Server代理作业活动监视器监控作业活动和查看作业历史记录.在实时监控和管理SQL Ser ...
- Spring Cloud第八篇 | Hystrix集群监控Turbine
本文是Spring Cloud专栏的第八篇文章,了解前七篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring Clo ...
- spring cloud系列教程第八篇-修改服务名称及获取注册中心注册者的信息
spring cloud系列教程第八篇-修改服务名称及获取注册中心注册者的信息 本文主要内容: 1:管理页面主机名及访问ip信息提示修改 2:获取当前注册中心的服务列表及每个服务对于的服务提供者列表 ...
- 【译】SQL Server索引进阶第八篇:唯一索引
原文:[译]SQL Server索引进阶第八篇:唯一索引 索引设计是数据库设计中比较重要的一个环节,对数据库的性能其中至关重要的作用,但是索引的设计却又不是那么容易的事情,性能也不是那么轻易就 ...
随机推荐
- JavaScript 中 4 种常见的内存泄露陷阱
了解 JavaScript 的内存泄露和解决方式! 在这篇文章中我们将要探索客户端 JavaScript 代码中常见的一些内存泄漏的情况,并且学习如何使用 Chrome 的开发工具来发现他们.读一读吧 ...
- 使用Spring的命名空间p装配属性-摘自《Spring实战(第3版)》
使用<property>元素为Bean的属性装配值和引用并不太复杂.尽管如此,Spring的命名空间p提供了另一种Bean属性的装配方式,该方式不需要配置如此多的尖括号. 命名空间p的sc ...
- Note++ 的快捷
Notepad++绝对是windows下进行程序编辑的神器之一,要更快速的使用以媲美VIM,必须灵活掌握它的快捷键,下面对notepad++默认的快捷键做个整理(其中有颜色的为常用招数): Ctrl+ ...
- 【转】select和epoll模型的差异
http://www.cppblog.com/converse/archive/2008/10/12/63836.html epoll为什么这么快 epoll是多路复用IO(I/O Multiplex ...
- Win7玩游戏偶尔自动跳转到桌面的解决办法[转]
新装的win7旗舰版SP1,怎么玩wow (魔兽世界.极品飞车.全屏游戏.按键精灵.挂机)总是过一会就自己返回桌面了.刚开始以为是显卡的毛病,更新了驱动还是一样(在这之前,排除病毒,其他驱动问题).因 ...
- ylbtech-Recode(记录)-数据库设计
ylbtech-dbs:ylbtech-Recode(记录)-数据库设计 -- =============================================-- DatabaseName ...
- JAVA 理解封装的概念,private私有的,public公有的
封装就是把不想或者不该告诉别人的东西隐藏起来,把可以告诉别人的公开. 做法:修改属性的访问权限来限制对属性的访问,并为每一个属性创建一对取值和赋值的方法,用于对这些属性的访问 通过封装,可以在给属性赋 ...
- 使用WebStorm/Phpstorm实现remote host远程开发
如果你的开发环境是在远程主机上,webstorm可以提供通过ftp/ftps/sftp等方式实现远程同步开发.这样我们可以就抛弃ftp. winscp等工具,通过webstorm编辑远程文件以及部署, ...
- Mac 上SVN上传.a文件
SVN默认是忽略.a文件,所以修改配置文件去掉忽略配置行的 *.a 通过终端打开配置文件: open ~/.subversion/config 把下面两行(也可能是一行)中的注释和*.a去掉, #gl ...
- SPR EAD NET 6
SPR EAD_NET6 下载地址 http://www.gcpowertools.com.cn/downloads/trial/Spread.NET/EN_SPREAD_NET6_SETUP_RA_ ...