Windows Workflow Foundation:创建自定义复合活动(一)

翻译|其它|编辑:郝浩|2006-05-12 12:26:00.000|阅读 1923 次

概述:

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>


适用于:
Windows Workflow Foundation Beta 2 版
Microsoft Visual C# 2.0 版
Visual Studio 2005

摘要本文构思了一个自定义复合活动,并表明如何在工作流中使用该活动。我们要讨论的这个活动是产品附带的“并行”活动的扩展,并对验证、编写自定义执行程序组件以及使用设计器类和主题类对用户界面进行样式设计进行了概述。(请注意示例程序文件中的程序员注释使用的是英文,本文中将其译为中文是为了便于参考。)

注意本文中的内容是使用 Beta 2 版编写的,将来可能需要进行一些更改才能适用于 Windows Workflow Foundation 的更高版本。

下载代码示例: Windows Workflow 示例 - ParallelIf.msi

本页内容

简介

可视类

行为

自定义活动

现用活动

详细信息

关于作者

简介

在本文中,我将深入探讨针对 Windows Workflow Foundation (WF) 开发自定义活动的详细信息,并提供包括组成自定义活动的所有部分的实现示例。尽管如此,首先还是提供有关活动的一些背景以及用于组成完整活动的类。

为了创建活动,您需要掌握许多类 - 在此示例中,将创建一个称为 ParallelIf 的活动,该活动的运行方式类似于常规的并行活动;但每个分支都有一个条件,即如果为 true,则确保执行该分支。同样,如果条件的评估结果为 false,则将执行子活动。

下面图 1 中所示图像表明了将在本文中使用的类。



图 1:组成活动的类

我特意将这些类分为左右两侧,左侧的类主要处理对活动进行设计时的情况,右侧的类则处理活动在工作流中使用时的行为。活动是唯一必需的对象 - 如果未明确定义,所有其他对象都将使用默认值。在下面的介绍中,术语“可视”和“行为”是我自己选择使用的。

可视类

有三个主要类用于构成活动的可视方面:ToolboxItemDesignerTheme。 类我将介绍的第一个类是 ToolboxItem 类。您可能会立刻想到该类用于定义对工具箱中图像进行的可视着色,它确实是这样,但它是将定义实际图像的任务委派给我们的老朋友 - ToolboxBitmap 属性(正如您可能知道的,自从 .NET Framework 1.0 以后,就有了该属性)。可以向 ToolboxItem 类添加相当多的内容,但我在这只重点说明要将您的活动构建到工具箱中所需的最低限度内容。

该类的主要作用是定义将您的活动从工具箱拖到工作流设计器中时会发生什么,因此您需要替换返回已初始化组件列表(即,您的活动以及您要添加的任何子活动)的 CreateComponentsCore 方法。下面缩减的代码表明了工具箱项示例以及如何将其挂钩到您的活动。

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Runtime.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;

namespace MNS.Activities
{
public class ParallelIfToolboxItem :ActivityToolboxItem
  {
protected override IComponent[] CreateComponentsCore(IDesignerHost host)
    {
CompositeActivity activity = new ParallelIfActivity();
activity.Activities.Add(new ParallelIfBranch());
activity.Activities.Add(new ParallelIfBranch());
activity.Activities.Add(new ParallelIfBranch());
return new IComponent[] { activity };
    }

// 为清晰表述而忽略了其它方法
  }

[ToolboxItem(typeof(ParallelIfToolboxItem))]
[ToolboxBitmap(typeof(ParallelIfActivity),
"Resources.ParallelIfActivity.png")]
public partial class ParallelIfActivity :CompositeActivity,
IActivityEventListener < ActivityExecutionStatusChangedEventArgs >
  {
    ...
  }
}

我已在此处定义了 ParallelIfToolboxItem 类并添加了 CreateComponentsCore 方法的实现。该方法用于构造新的父活动 (ParallelIfActivity),然后添加三个 ParallelIfBranch 活动作为新活动的子活动(在本文后面将定义这些活动)。之后活动返回给调用者。因此,当您将该活动放到设计器中时,它将创建活动并在该活动中构造子分支。显然,您还可以在此处为活动属性设置适当的默认值。

然后显示了 ParallelIfActivity 类的第一个部分,定义了将工具箱项挂钩到活动以及图像的资源的属性。ToolboxBitmap 属性有许多替换值,由于我通常沿用 Microsoft 在内部使用的同一方法,因此我使用了这个替换值。在我的项目中,使用了一个 Resources 目录,如图 2 中所示。

图 2:Resources 目录中的自定义位图

我在此处创建了一个图像,并将其定义为嵌入的资源,以便在编译期间它能包含在程序集中。用于工具箱项的图形应该为 16 X 16 像素,颜色深度最高为每像素 256 位。

Designer 类

为了在窗体上绘制活动时更改活动的可视方面,需要添加自定义设计器类,该类通常衍生自 ActivityDesignerCmpositeActivityDesigner(如果为复合活动)。设计器通过 [Designer] 属性链接到活动,方式与本文中介绍的其他关联类的所示方式相同。

在设计器中,您可以添加代码以提供完整的自定义绘制功能(如果需要),但在此示例中,将使用自定义主题,该主题允许我更改活动的许多可视方面,而完成此操作毫不费力。

下面的代码表明了设计器类的实现,以及如何通过 [Designer] 属性将其与 ParallelIfActivity 类关联。

using System;
using System.Collections.ObjectModel;
using System.Workflow.ComponentModel.Design;

namespace MNS.Activities
{
[Designer(typeof(ParallelIfDesigner))]
public partial class ParallelIfActivity :CompositeActivity, ...
  {
    ...
  }

public class ParallelIfDesigner :ParallelActivityDesigner
  {
public override bool CanInsertActivities(HitTestInfo 
insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
    {
return false;
    }
public override bool CanMoveActivities(HitTestInfo moveLocation, 
ReadOnlyCollection<Activity> activitiesToMove)
    {
return true ;
    }
public override bool CanRemoveActivities(ReadOnlyCollection<Activity> 
activitiesToRemove)
    {
return true ;
    }
protected override CompositeActivity OnCreateNewBranch()
    {
return new ParallelIfBranch();
    }
  }
}

设计器类用于确定在工作流设计器中会发生什么,因此我在此替换了 CanInsertActivities 以返回 false。此方法会在某活动从工具箱拖到 ParallelIfActivity 中时调用,并且我始终在此返回 false,因为只有 ParallelIfBranch 可以作为 ParallelIfActivity 的直接子活动(由于是使用 OnCreateNewBranch() 方法添加 ParallelIfBranch 的,因此它不在工具箱中)。您可以扩展此处理过程,以检查放置何种类型的活动,并可允许某些活动而拒绝其他活动。这完全取决于您。

我从 CanRemoveActivitiesCanMoveActivities 返回 true,因为在我的设计器中支持这两者。对 ParallelActivityDesignerCanRemoveActivities 方法的默认处理是检查定义了多少子分支,以及允许删除某分支(仅当这可确保至少仍有两个定义的分支时)。我替换了此行为,将其改为如果可用分支少于两个,则验证程序发出错误。

复合活动(例如此活动)需要一些创建新分支的方法,在此分支是 ParallelIfActivity 的直接子活动。当您右键单击活动,然后选择 Add Branch(添加分支)时,即在设计器中使用 OnCreateNewBranch 方法,如图 3 中所示。

图 3:在设计器中添加新分支

之前,再次设置分支的相应属性(如果需要)。上面的图像中也显示了下面定义的主题类的输出。

从验证程序(下文予以介绍)发出的每个错误都可以包含一些自定义数据,此数据包含在哈希表中,并且应该可序列化,因为验证程序和设计器在独立的应用程序域中运行。我使用了此数据来添加字符串值,用于指示定义的分支少于两个。之后在我的设计器中,我替换 OnExecuteDesignerAction 并检查是否存在此额外数据,如果发现存在,则向活动添加分支,直至达到两个。此代码如下所示。

private void OnAddBranch(object sender, EventArgs e)
{
CompositeActivity activity1 = this.OnCreateNewBranch();
CompositeActivity activity2 = base.Activity as CompositeActivity;
if ((activity2 != null) && (activity1 != null))
    {
int num1 = this.ContainedDesigners.Count;
Activity[] activityArray1 = new Activity[] { activity1 };
CompositeActivityDesigner.InsertActivities(this, new 
ConnectorHitTestInfo(this, HitTestLocations.Designer, 
activity2.Activities.Count), new 
List<Activity>(activityArray1).AsReadOnly(), string.Format("正在添加分支 {0}", activity1.GetType().Name));
if ((this.ContainedDesigners.Count > num1) && 
(this.ContainedDesigners.Count > 0))
                {
        this.ContainedDesigners[this.ContainedDesigners.Count - 1].EnsureVisible();
                }
    }
}

protected override void OnExecuteDesignerAction(DesignerAction designerAction)
{
// 检查我的用户数据是否存在...
if (designerAction.UserData.Contains("LESS_THAN_TWO"))
    {
        CompositeActivity parent = this.Activity as CompositeActivity;

        if (null != parent)
        {
           while ( parent.Activities.Count < 2 )
           OnAddBranch(this, EventArgs.Empty);
        }
    }
else
base.OnExecuteDesignerAction(designerAction);
}

因此,如果用户从 ParallelIfActivity 删除所有活动,则在用户界面上将显示警告,提示如果单击,将向设计器中添加适当数量的子分支。

Theme 类

Theme 类用于定义活动的可视表示,在此您可以定义属性,例如,在活动中使用的线条的颜色、线端(如箭头等)、用于绘制图像轮廓的笔以及绘制图像时使用的背景刷。

Theme 类有许多其他属性,因此您可以了解一下还可以定义其他什么属性。定义主题很简单,并会使您的活动格外出众 - 尽管我建议不要采用您的用户不喜欢的过于夸张的颜色。

using System;
using System.Drawing.Drawing2D;
using System.Workflow.ComponentModel.Design;

namespace MNS.Activities
{
[ActivityDesignerTheme( typeof (ParallelIfTheme))]
public class ParallelIfDesigner :ParallelActivityDesigner
  {
    ...
  }

public class ParallelIfTheme :CompositeDesignerTheme
  {
public ParallelIfTheme(WorkflowTheme theme)
: base(theme)
    {
        this.ShowDropShadow = true;
        this.ConnectorStartCap = LineAnchor.None;
        this.ConnectorEndCap = LineAnchor.None;
        this.BorderStyle = DashStyle.Dash;
    }
  }
}

主题的类型主要有两种 - 用于常规活动的主题和用于复合活动的主题。用于着色复合活动的主题是可用于常规活动的主题的超集。ActivityDesignerTheme 基类用于常规活动,而在此使用 CompositeDesignerTheme 是因为我的 ParallelIfActivity 包含子活动。我只定义了主题来设置边框样式、投影以及线端。

主题通过使用 [ActivityDesignerTheme] 属性附加到设计器,如上面的代码中所示。而设计器通过使用 [Designer] 属性附加到活动,如前面的代码段中所示。


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com


为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP