FtpGetFileActivity类
其中接下来要做的一个更重要的事情是创建一个自定义验证器。尽管你可以使用该FTP活动了,因为它现在已经存在,但此时它是不完整的引入到工作流视图设计器中的。它所缺少的是属性验证。我们就来看看怎样添加一个验证器。
创建一个自定义ActivityValidator
现在,我确信你已经看到过小红色圆圈内包含一个感叹号的标记出现在那些在工作流视图设计器中没有完成相应配置的活动中。
例如,在Code活动中假如没有为它设置ExecuteCode属性的话将显示这个指示标记。原因是什么呢?
答案是活动验证器强迫这样做。验证器检查和它相关联的活动的属性并在需检查的任何属性缺失和无效的时候就把错误添加进一个错误集合中。当设计器的状态发生改变(换句话说,就是在添加了新活动或者属性发生改变的时候)以及工作流被编译的时候会要求验证器重新对它适用的活动的属性进行判定。
验证器能选择是否对属性的配置不进行验证,它也能把它们标记为警告或者是不可接受的错误。FTP活动有三个属性,其中一个很关键(就是URL)。其它两个可以不管,这将产生默认(匿名)用户的身份验证。但我们实现我们的验证器时,我们将把缺少URL的情况(或者在主工作流活动中缺少对URL属性的绑定)标记为一个错误。假如省略了用户名或密码的话我们将产生警告信息来提示将使用匿名登录。
为FtpGetFileActivity工作流活动创建一个验证器
1.WF中的活动验证器其实是一个类,因此我们要在FtpActivity项目中添加一个新类。类的名称命名为“FtpGetFileActivityValidator.cs”。
2.在源文件中添加下面的名称空间:
using System.Workflow.ComponentModel.Compiler;
3.当创建了FtpGetFileActivityValidator的新类创建后,它是一个private类型的类。而且,WF活动验证器必须使用ActivityValidator作为基类。因此在源文件中对该类添加public关键字以及一个ActivityValicator基类来更改类的定义:
public class FtpGetFileActivityValidator : ActivityValidator
4.为了实际去执行验证,你必须重写Validate方法。这里我们将对属性进行检查,假如它们没有(设置)的话,你将把一个错误添加到设计器提供的错误集合中。下面是你需要添加到FtpGetFileActivityValidator类中去的完整的Validate重写方法。
重写的Validate方法
5.FtpGetFileActivityValidator类现在就完成了,但我们实际上并没有通知WF去执行验证。为此,回到FtpGetFileActivity类中,在该类定义的前面为该类添加下面的特性标记:
[ActivityValidator(typeof(FtpGetFileActivityValidator))]
6.生成FtpActivity项目,修正可能出现的任何错误。
完整的验证器代码如清单13-2所示。现在,当你拖拽该FtpGetFileActivity到你的工作流中去的时候,假如你忘了指定该URL或者你没有为提供的URL创建绑定的话,工作流不能编译。并且,假如你没有提供用户名或密码,或者你甚至没有在Visual Studio中使用属性面板对它们进行绑定的话,你将收到警告信息。
清单13-2 FtpGetFileActivityValidator.cs的完整代码 提供工具箱位图
FtpGetFileActivityValidator类
我们下面将在我们的活动中做的事情是为它提供一个工具箱位图。这不是一个严格意义上的WF任务。这种功能被集成到.NET中,主要用于为Visual Studio设计器提供支持。它也并不难做到。
为FtpGetFileActivity工作流活动指定一个工具箱位图
1.下载本章的示例代码,你将找到一个名称为FtpImage的位图文件。把FtpImage文件从Windows Explorer窗口中拖拽到FtpActivity项目的树形控制节点下面,这会把该文件复制并添加到你的项目目录中。
2.然后,你必须把该位图作为资源编译进你的程序集中。在解决方案资源管理器的FtpActivity项目中选中FtpImage文件以激活它的属性。更改“生成操作”属性,把它从“编译”改为“嵌入的资源”。
3.和验证器一样,只是把一个位图编译进你活动的程序集中是不够的。你也必须通知Visual Studio该活动有一个相关的工具箱位图。和先前一样,你使用一个特性来通知Visual Studio这件事。把下面的特性添加到FtpGetFileActivity类的定义中(就像你在前面一节添加ActivityValidator一样):
[ToolboxBitmap(typeof(FtpGetFileActivity), "FtpImage.bmp")]
备注:ToolboxBitmapAttribute不是WF所特有的。它可以用到任何的控件。看看http://msdn2.microsoft.com/en-us/library/4wk1wc0a(VS.80).aspx可获得更多信息。
4.生成FtpActivity项目。不应出现任何错误,假如有的话,修正它们。
假如你此刻创建一个顺序工作流并把这个活动拖拽到该工作流中去的话,这个活动会以相当普通的外观呈现出来。默认呈现出的外观是一个以黑色圆角作为边框并用白色填充的矩形。想做得更好吗?看看下面怎么做。
修改活动在工作流视图设计器中的外观
工作流视图设计器其实基于通用的Visual Studio设计器。自.NET 1.0以来,.NET Framework中就有组件帮助你把你的自定义对象集成到通用功能的设计器中。这些组件中的一个就是Designer特性,它嵌入代码中被执行,视图设计器使用它去控制如对象的展示和外观之类的事情。
WF通过提供一种机制延伸了这一概念,它通过一个theme来为可视化活动的展现提供支持。主题(theme)实际上只不过是一个设计器类,它包含许多的属性,你能设置它们以便去控制你的活动被怎样绘制。你能控制呈现的颜色、边框线的风格及颜色等等。
你也能控制它在视图设计器中的行为。例如,你能把一些东西添加到使用鼠标右键点击活动时所弹出的快捷菜单中。主题和行为操作两者都要求你去写一个派生于ActivityDesigner或CompositeActivityDesigner(针对组合活动)的类。对于我们的例子,我们将创建一个专门的命名为FtpGetFileActivityDesinger的设计器类。
添加一个可视化设计器到FtpGetFileActivity工作流活动中
1.这里你将以和前一节同样的方式开始我们的工作:创建一个新类。为此,向FtpActivity项目中添加一个名称为FtpGetFileActivityDesigner.cs的类文件。
2.向该源文件中插入下面的名称空间,把它们放到已存在的名称空间语句的下面:
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Workflow.Activities;
using System.Workflow.ComponentModel.Design;
3.因为你正创建的设计器类派生自ActivityDesigner,因此你需要修改源文件中的类定义。使用下面的类定义来替换Visual Studio为你自动生成的类定义:
public class FtpGetFileActivityDesigner : ActivityDesigner
备注:再重复一次,因为这是一个基本活动,因此你正创建的设计器类派生自ActivityDesigner。但是,假如这个活动是一个组合活动的话,你应该使用CompositeActivityDesigner类来作为基类。
4.ActivityDesigner提供了几个虚拟的属性和方法,你能重写它们以便把行为外观添加到视图设计器中。例如Verbs属性可以让你添加上下文选择菜单。做这些相当地简单,从行为外观的角度来看FTP活动不需要特别的支持,但它在调节视觉方面是很不错的。为做这些,首先在FtpGetFileActivityDesigner类定义的前面添加下面的特性标记:
[ActivityDesignerThemeAttribute(typeof(FtpGetFileActivityDesignerTheme))]
5.你刚刚添加的特性指定了一个包含绘制属性任务的设计器主题类,我们现在就来创建这个类。寻找FtpGetFileActivityDesigner类的结束(右边)大括号,在该大括号的下面添加如下这个内部(internal)类:
备注:组合活动也有它们自己的设计器主题类:CompositeDesignerTheme。那是因为组合活动需要去呈现子活动,并且你可能想在视觉外观上进行更严格的控制。
6.在有了验证器和工具箱位图后,你需要为FtpGetFileActivity类添加一个特性来通知工作流视图设计器你有为展示你的活动所需的基于ActivityDesigner的信息。
[Designer(typeof(FtpGetFileActivityDesigner), typeof(IDesigner))]
7.编译该项目,修正任何出现的编译错误。
FtpGetFileActivityDesigner的完整文件如清单13-3所示。假如我们需要的话,我们能在设计器类上做更多的工作,但在这个例子中,该设计器类的存在仅仅只是添加主题。该活动将在工作流视图设计器中以银色到白蓝色的颜色水平渐变并以实心边框线的风格呈现出来。
清单13-3 FtpGetFileActivityDesigner.cs的完整源代码 还剩下一个细节:当它加载进工具箱后,FtpGetFileActivity的名称和图标都将会展示出来。
FtpGetFileActivityDesigner.cs的完整源代码
把自定义活动集成到工具箱中
如你所知,当你的活动被装到Visual Studio工具箱中后,ToolboxBitmapAttribute会显示一个和你的活动关联的图标。但碰巧的是,你能做比刚刚显示一个位图更多的事。
例如组合活动,通常要为其正常运行创建所必须的子活动。一个极好的例子是IfElse活动。当你拖拽一个IfElse活动到你的工作流中的时候,它会自动填充一个左右分支活动。在这里我不会显示怎样做这些,因为我们正创建的是一个基本活动。但在这节的末尾我将提供一个获取更多信息的链接以及创建组合活动并预先用子活动来填充它们的示例代码。
因此,如果我们不添加子活动的话,我们还需要完成些什么事才能把我们的活动集成到工具箱中呢?对这件事来说,如没有其它的指示,Visual Studio将把你的活动加载进工具箱中并使用类的名字作为它显示的名字。因为有其它的WF活动没有使用它们的类名来作为显示名,因此我们将对默认的行为进行重写并提供一个更像是真正的标准WF元素的显示名(不使用类名来作为显示名)。尽管我们所有要调整的事情就是这些,但你也能修改像包含一个描述信息、你的公司名称以及一个版本号在内的其它事情。
你也能提供过滤,以便让你的活动只在基于工作流中使用时呈现,但你很快将使用的ActivityToolboxItem基类为你提供了这种行为。
为FtpGetFileActivity工作流活动添加工具箱集成
1.和前面两节一样,你要创建一个新类,在FtpActivity项目中添加一个名称为FtpGetFileActivityToolboxItem.cs的类文件。
2.添加下面的名称空间,把它们放到现存的名称空间的下面:
using System.Workflow.ComponentModel.Design;
3.你正创建的类必须从ActivityToolboxItem派生。因此,你需要修改Visual Studio为你创建的默认的类定义。用下面的内容替换该类的类定义。
using System.Runtime.Serialization;
class FtpGetFileActivityToolboxItem : ActivityToolboxItem
4.FtpGetFileActivityToolboxItem类必须被标记为可序列化的,因此在刚才类定义的前面添加Serializable特性。
[Serializable]
5.现在添加该类的主要部分。你需要三个构造器:一个默认的构造器,一个带参数的构造器和一个序列化构造器。每一个构造器都将调用InitializeComponent来指定它的显示名称。
备注:有一个虚拟方法Initialize,你可以重写它去指定要显示的名称。但是这个方法并不总会被调用。因此提供我们自己的InitializeComponent方法是确保指定的显示名称在所有情况下都有效的最好方式。
6.为确保你刚刚创建的ToolboxItem被FTP活动使用,需要把下面的特性添加到你已经为FtpGetFileActivity添加的一组特性的下面。
[ToolboxItem(typeof(FtpGetFileActivityToolboxItem))]
7.编译FtpActivity项目,修正任何可能出现的编译错误。
随着这最后的一个步骤,你的自定义活动就完成了。但是,FileGrabber应用程序是不完整的。你需要添加一个使用FtpGetFileActivity的工作流,并为FileGrabber应用程序添加必须的代码以便调用该工作流。我们首先创建该工作流。
添加一个工作流并使用FtpGetFileActivity工作流活动
1.右键点击FileGrabber解决方案,然后选择“添加”。从子菜单中选中“新建项目”。
2.新建的项目类型选择“顺序工作流库”,名称命名为“GrabberFlow”。
3.Visual Studio添加了一个新的顺序工作流库后会打开工作流视图设计器,让你可直接开始编辑你的工作流。打开Visual Studio工具箱后,你应该在那里能找到FtpGetFileActivity。
备注:你或许会惊讶,漂亮的小FTP位图到哪里去了(取而代之的是一个蓝色齿轮图标),以及你在FtpGetFileActivityToolboxItem类中添加的显示文本为什么没有在工具箱中显示出来。这是因为FtpGetFileActivity由当前解决方案中的一个程序集支持。我将在你完成了该工作流后来描述解决这些问题的办法。
4.拖拽一个FtpGetFileActivity到你的设计器界面上。
5.带感叹号标记的红点指明了当前存在一些验证错误。并且事实上,假如你把鼠标放到向下的箭头上并单击的话,你将看到详细的验证失败信息。它看起来眼熟吗?哦...它是你在前面章节创建活动验证类时所插入的相关验证错误信息。
6.FileGrabber主应用程序要能够把用户名、密码和文件的URL传进你的工作流中。因此你需要在你的工作流中为所有这些值都提供一个属性。这里有一个很棒的方式来完成这些任务:让Visual Studio为你添加它们。假如你选中FTP活动然后在属性面板中看看它的属性的话,你将看到你为活动添加好的三个属性:FtpUrl、FtpUser和FtpPassword。为了让你首先清除错误的条件,你需要选中FtpUrl属性以激活浏览(...)按钮。点击该浏览按钮。
7.这将激活“将‘FtpUrl’绑定到活动的属性”对话框。点击“绑定到新成员”选项卡,在“新成员名称”中输入“FtpUrl”,确保选中的是“创建属性”。最后点击“确定”。(注意现在带感叹号标记的红点消失了。)
8.按照相同的步骤(步骤6和步骤7)添加一个新的FtpUser属性和一个新的FtpPassword属性。当你完成这些后,属性面板显示的为所有这三个属性的绑定效果如下图所示:
9.编译该工作流项目,假如存在错误的话,请纠正这些错误。
我在第三步中提到过,我会描述怎样把FtpGetFileActivity加载进工具箱中去显示出你在前面章节中添加的实际已存在的元数据。下面就是你要做的。
把FtpGetFileActivity工作流活动加载进工具箱中
1.对这一工作来说,你必须在工作流视图设计器中有一个工作流。(工具箱会过滤掉不适合的组件。)GrabberFlow工作流应该被加载进工作流视图设计器中了,如没有的话,重新加载它并打开工具箱。在工具箱内容体(不是标题)上点击鼠标右键,这将弹出上下文菜单,然后选择“选择项”。
2.这将打开“选择工具箱项”对话框。单击“活动”选项卡然后点击“浏览”按钮。
3.点击“浏览”将打开一个常见的文件对话框。使用导航工具,浏览并定位到你本地文件系统中已编译的FtpActivity项目对应的目录,通常为“Chapter13FileGrabberFtpActivitybinDebug”(或者为“Release”,这取决于你所选择的生成模式)。选中FtpActivity.dll文件,点击“打开”。然后点击“确定”关闭“选择工具箱项”对话框。
4.这就把FtpGetFileActivity加载进工具箱中了,并且你应该会看到你在前面所添加的自定义图标和显示文本。
我们最后的任务是去添加在主应用程序中开始该工作流所需的代码。
执行FtpGetFileActivity工作流
1.在代码视图模式下打开Form1.cs文件。
2.除了真正启动工作流实例所需的代码外,你需要的所有代码我都已经为你添加好了。该代码将放进Get_Click事件处理程序中。因此找到Get_Click事件处理程序,在末尾添加如下代码:
Get_Click事件处理程序
// Process the request, starting by creating the parameters
Dictionary<string, object> parms = new Dictionary<string, object>();
parms.Add("FtpUrl", tbFtpUrl.Text);
parms.Add("FtpUser", tbUsername.Text);
parms.Add("FtpPassword", tbPassword.Text);
// Create instance.
_workflowInstance = _workflowRuntime.CreateWorkflow(typeof(GrabberFlow.Workflow1), parms);
// Start instance.
_workflowInstance.Start();
3.因为你正使用的工作流来自于GrabberFlow名称空间,因此你需要添加对该工作流程序集的项目级引用。
4.按下F5(或者Ctrl+F5)执行FileGrabber。假如你提供了一个有效的FTP URL文件地址,该文件会被下载吗?(注意该文件将被下载并放到和你的应用程序的可执行文件相同目录的位置中。)
在这一章,我们创建了一个基本活动。这些必需的步骤对于创建一个组合活动来说也是相似的,只是稍微多了一些调用。(例如,你创建的ToolBoxItem就多些额外的代码去方便对所容纳的活动进行添加。)假如你想阅读关于组合活动创建的更多资料的话,你可以在http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/parallelif.asp中找到