The Life of Windwolf

while(life.Length > 0) { Creating(); }

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

公告

Windows Workflow Foundation之旅(五)——指南3(创建自定义活动)

翻译自: ms-help://MS.WinWF.v1.EN/WinWF_GettingStarted/html/8b6344bc-c879-41c5-babf-74e91c34d281.htm

 

 

WWF包含了一组丰富的通用用户活动,这些能满足绝大多数的场景的需求。但有时,我们还是会碰到需要一些更加自定义的活动的场景。WWF SDK拥有一些可扩展的特性,能使你轻松的创建自定义的活动,并把他们应用到你的解决方案中。在这一节中,我们会编写一个自定义活动,用来根据传入工作流的参数,从网页中下载文本。

 

创建一个网页解析自定义活动

 

这个自定义活动会根据传入活动的网页属性集,从网页中下载文本。页面一旦下载完毕,活动就会发出一个网页下载完毕的事件,并把网页数据值发回工作流。

 

创建WebTearActivity

 

WebTear类继承自System.Workflow.ComponentModel.Activity。当你定义了一个自定义活动时,把ToolboxItemAttributes属性应用到类上,并指明为ActivityboxItem类型。以下的代码就是一个最小的自定义活动。

using System;
using
 System.ComponentModel;
using
 System.Workflow.ComponentModel;
using
 System.Workflow.ComponentModel.Design;
using
 System.Workflow.ComponentModel.Compiler;
 
namespace
 Microsoft.Samples.Workflow.Quickstarts.CustomActivity
{
    [ToolboxItemAttribute(
typeof
(ActivityToolboxItem))]
    
public class
 WebTear : System.Workflow.ComponentModel.Activity
    
{
    }

}


 

定义活动属性

 

自定义活动属性的定义和WinForm控件属性的定义类似。当你定义一个自定义活动的属性时,使用DependencyProperty来存储属性的属性。这能让各种不同类型的属性都能一致地有效地工作。在实际定义属性时,你可能还会用到DependencyProperty中的方法,所以,不要把这个字段定义成private

活动中的一个属性可以应用许多不同的特性。这些特性通常都是用来支持WWF设计器的工作的。我们的这个属性应用了一下的特性:

1.  CategoryAttribute:在设计器的属性窗口中,这个属性位于那个分类下。

2.  DescriptionAttribute:设计器属性窗口中显示的属性描述。

3.  BrowsableAttribute:这是一个布尔值,指示了是否在属性窗口中显示这个属性。

4.  ValidationVisibilityAttribute:指定了如何验证属性的值。验证选项包括:可选Optional、必需Required、隐藏Hidden

5.  DesignerSerializationVisibilityAttribute:指定了是否和如何序列化这个属性。选项包括:可见Visible、隐藏Hidden、内容Content

以下的代码示例了如何定义WebPage属性。

public static DependencyProperty WebPageProperty =
    DependencyProperty.Register(
"WebPage"typeof(System.String), typeof (Microsoft.Samples.Workflow.Quickstarts.CustomActivity.WebTear ) );
 
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[ValidationVisibilityAttribute(ValidationVisibility.Optional)]
[BrowsableAttribute(
true
)]
[DescriptionAttribute(
"Web page to download"
)]
[CategoryAttribute(
"WebTear Property"
)]
public string
 WebPage
{
    
get

    
{
        
return ((string)(base
.GetValue(Microsoft.Samples.Workflow.Quickstarts.CustomActivity.WebTear.WebPageProperty)));
    }

    
set
    
{
        
base
.SetValue(Microsoft.Samples.Workflow.Quickstarts.CustomActivity.WebTear.WebPageProperty, value);
    }

}


 

重载Execute方法

 

当你创建了一个自定义活动,运行时,工作流引擎会调用活动的Execute方法来执行活动实际的操作。这个方法是在基类中定义的,但你可以重载这个方法,以适应你的活动的功能。

WebTear活动会在Execute方法中下载请求的网页,并在下载完成后引发一个事件,将页面数据发回工作流。我们需要定义一个PageFinishedEventArgs类用于事件参数,这个类中有一个Data字段用来存放网页数据。这些数据会在之后被工作流中的事件处理函数访问到。一旦数据下载完毕,Execute方法返回一个Status.Closed枚举值,来通知工作流引擎活动已经完成执行了。

一下的代码演示了如何定义PageFinishedEventArgs

public class PageFinishedEventArgs
{
    
private string
 data;
 
    
public PageFinishedEventArgs( string
 data )
    
{
        
this.data =
 data;
    }

 
    
public string Data
    
{
        
get return data; }

    }

}


 

以下的代码演示了如何实现Execute方法。

public delegate void PageFinishedEventHandler( object sender, PageFinishedEventArgs e );
public event
 PageFinishedEventHandler PageFinished;
 
protected override
 Status Execute(ActivityExecutionContext context)
{
    System.Net.WebClient client 
= new
 System.Net.WebClient();
    
string
 pageData;
 
    
try

    
{
        
// Download the web page data

        pageData = client.DownloadString(WebPage);
    }

    
catch (Exception e)
    
{
        pageData 
=
 e.Message;
    }

 
    
// Raise the PageFinished event back to the host
    PageFinished(nullnew PageFinishedEventArgs(pageData));
 
    
// Notifiy the runtime that the activity has finished

    return Status.Closed;
}


 

WebTear活动创建顺序工作流

 

此时,我们已经创建好了下载网页的自定义活动。现在我们创建一个简单的顺序工作流,来测试一下这个自定义活动的功能。

这个工作流只包含一个活动,就是我们的WebTear活动。要下载的网页地址被传到工作流的Parameters集合中,这个的值用来设置活动的WebPage属性。最后,当活动结束下载后,触发事件,工作流会从事件参数中提取网页数据,并把数据通过Parameters集合中的out参数发回宿主程序。以下代码演示了顺序工作流的实现

using System;
using
 System.ComponentModel;
using
 System.Workflow.ComponentModel;
using
 System.Workflow.ComponentModel.Design;
using
 System.Workflow.ComponentModel.Compiler;
using
 System.Workflow.Activities;
 
namespace
 Microsoft.Samples.Workflow.Quickstarts.CustomActivity
{
    
public sealed partial class
 WebTearActivityWorkflow : SequentialWorkflow
    
{
        
private string
 webSite;
        
private
 WebTear webTear1;
 
        
public
 WebTearActivityWorkflow()
        
{
            InitializeComponent();
        }

 
        
private void InitializeComponent()
        
{
            System.Workflow.ComponentModel.ActivityBind activitybind1 
= new
 System.Workflow.ComponentModel.ActivityBind();
            System.Workflow.ComponentModel.ParameterDeclaration WebPage 
= new
 System.Workflow.ComponentModel.ParameterDeclaration();
            System.Workflow.ComponentModel.ParameterDeclaration PageData 
= new
 System.Workflow.ComponentModel.ParameterDeclaration();
            
this.webTear1 = new
 Microsoft.Samples.Workflow.Quickstarts.CustomActivity.WebTear();
            
//
 
            
//
 webTear1
            
// 

            this.webTear1.ID = "webTear1";
            activitybind1.ID 
= "/Workflow"
;
            activitybind1.Path 
= "webSite"
;
            
this.webTear1.PageFinished += new Microsoft.Samples.Workflow.Quickstarts.CustomActivity.WebTear.PageFinishedEventHandler(this
.webTear1_PageFinished);
            
this
.webTear1.SetBinding(Microsoft.Samples.Workflow.Quickstarts.CustomActivity.WebTear.WebPageProperty, ((System.Workflow.ComponentModel.Bind)(activitybind1)));
            
//
 
            
//
 WebTearActivityWorkflow
            
// 

            this.Activities.Add(this.webTear1);
            
this.DynamicUpdateCondition = null
;
            
this.ID = "WebTearActivityWorkflow"
;
            WebPage.Direction 
=
 System.Workflow.ComponentModel.ParameterDirection.In;
            WebPage.Name 
= "WebPage"
;
            WebPage.Type 
= typeof
(System.String);
            WebPage.Value 
= null
;
            PageData.Direction 
=
 System.Workflow.ComponentModel.ParameterDirection.Out;
            PageData.Name 
= "PageData"
;
            PageData.Type 
= typeof
(System.String);
            PageData.Value 
= null
;
            
this
.Parameters.Add(WebPage);
            
this
.Parameters.Add(PageData);
            
this.Initialized += new System.EventHandler(this
.InitVars);
 
        }

 
        
private void InitVars(object sender, EventArgs e)
        
{
            webSite 
= this.Parameters["WebPage"
].Value.ToString();
        }

 
        
private void webTear1_PageFinished(object sender, PageFinishedEventArgs e)
        
{
            
this.Parameters["PageData"].Value =
 e.Data;
        }

    }

}


 

创建宿主程序

 

这里的宿主程序是一个Winform程序,它有一个TextBox来输入要下载的url,当点击Go按钮,工作流开始运行,并执行WebTear活动开始下载网页。工作流运行完后,宿主程序从WorkflowCompleteEventArgs对象中获得网页数据,并把它显示在另一个TextBox中。以下代码演示了如何实现宿主程序(译者注:私自去掉了不重要的代码,要看完整的自个儿去msdn上找,呵呵)。

……

namespace
 Microsoft.Samples.Workflow.Quickstarts.CustomActivity
{
    
public class
 MainForm : Form
    
{
        
private
 System.Windows.Forms.Label addressCaption;
        
private
 System.Windows.Forms.TextBox address;
        
private
 System.Windows.Forms.TextBox data;
        
private
 System.Windows.Forms.Button goButton;
 
        
private
 WorkflowRuntime workflowRuntime;
 
        
public
 MainForm()
        
{
            InitializeComponent();
 
            workflowRuntime 
= new
 WorkflowRuntime();
            workflowRuntime.StartRuntime();
 
            workflowRuntime.WorkflowCompleted 
+= new EventHandler<WorkflowCompletedEventArgs>
(workflowRuntime_WorkflowCompleted);
        }

 
        
void workflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
        
{
            
// Retrieve the downloaded page data

            if (data.InvokeRequired)
                data.Invoke(
new EventHandler<WorkflowCompletedEventArgs>
(workflowRuntime_WorkflowCompleted), sender, e);
            
else

                data.Text 
= e.OutputParameters["PageData"].ToString();
        }

 
        
private void goButton_Click(object sender, EventArgs e)
        
{
            Type type 
= typeof
(Microsoft.Samples.Workflow.Quickstarts.CustomActivity.WebTearActivityWorkflow);
 
            
//
 Sending the data to the workflow.
            
// First create the required property set 

            Dictionary<stringobject> properties = new Dictionary<stringobject>();
            properties.Add(
"WebPage"
, address.Text);
            properties.Add(
"PageData"""
);
 
            workflowRuntime.StartWorkflow(type, properties);
        }

 
        ……
    }

}


 

posted on 2005-12-20 09:50 windwolf 阅读(...) 评论(...) 编辑 收藏