当前位置: 代码迷 >> 综合 >> Beginning WF 4.0——翻译(第七章扩展内置的活动)
  详细解决方案

Beginning WF 4.0——翻译(第七章扩展内置的活动)

热度:19   发布时间:2024-01-03 09:39:12.0

前六单请参见苦-咖啡:http://www.cnblogs.com/kukafeiso/category/250073.html

谢谢苦-咖啡的辛苦分享,偶这几天闲来没事,翻译了第7章出来,有不对的地方欢迎大家指正。

 

第七章 扩展内置的活动

在这一章,你将继续完善订单价格规则。在这过程中,我将使用两种技术来演示扩展内置的活动:自定义活动和InvokeMethod活动。

 

重新利用Chapter6项目

打开Visual Studio 2010 创建一个新的项目,选择Blank Solution模板,如图Figure7-1所示。输入解决方案名为Chapter7

Figure 7-1. Creating a blank solution

 

 

复制Chapter06目录下的OrderProcess文件夹到Chapter07的目录下。在Solution Explorer中,右击Chapter07解决方案,选择Add>Existing ProjectAdd Existing Project对话框会出现。选择Chapter07/OrderProcess下的OrderProcess.csproj文件。(这跟上一章的做法是一样的。)

 

使用自定义活动

  当前项目的对于所有项价格固定为$10,你可以创建自定义一个可以根据ItemCode属性查询item价格的自定义活动。打开Order.cs程序文件并添加如下类的定义,下面类定义的item属性将通过自定义活动返回。

    //---------------------------------------------

    // Define the structure returned by the

    // LookupItem custom activity

    //---------------------------------------------

    public class ItemInfo

    {

        public string ItemCode { get; set; }

        public string Description { get; set; }

        public decimal Price { get; set; }

    }

 

提醒:WF4.0不再允许在你的流程定义中添加任何可执行的代码,所有的代码只能在活动中执行。在以前的版本中,你可以使用CodeActivity类并且在代码旁类写你自己的代码,使用WF4.0,CodeActivity将不再是具体类了,而是大部分内置活动的基类且是抽象的类(可以作为自定义活动的基类),但它不能在workflow中直接使用了。这意味着在WF4.0中,你会发现你自己将要写很多的自定义活动。幸运的是,你将很容易的实现这些定自义活动的(接下来你将在本章中看到如何轻易地实现)

 

实现一个自定义活动

  Solution Explorer中,右击OrderProcess项目选择Add->New Item,在新建Item对话框中选择Code Activity项,并输入类名为LookupItem.cs,如下图Figure 7-2

Figure 7-2. Creating a custom activity

Listing 7-1. LookupItem Class

using System;

using System.Activities;

namespace OrderProcess

{

    public sealed class LookupItem : CodeActivity

    {

        public InArgument<string> ItemCode { get; set; }

        public OutArgument<ItemInfo> Item { get; set; }

        protected override void Execute(CodeActivityContext context)

        {

            ItemInfo i = new ItemInfo();

            i.ItemCode = context.GetValue<string>(ItemCode);

            switch (i.ItemCode)

            {

 

                case "12345":

                    i.Description = "Widget";

                    i.Price = (decimal)10.0;

                    break;

                case "12346":

                    i.Description = "Gadget";

                    i.Price = (decimal)15.0;

                    break;

                case "12347":

                    i.Description = "Super Gadget";

                    i.Price = (decimal)25.0;

                    break;

            }

            context.SetValue(this.Item, i);

        }

    }

}

 

正如工作流程有输入和输出参数一样(第四章已经解释过了),活动也有输入和输出参数。事实上,这些必须设置内置类的属性是活动的参数(比如WriteLine活动的Text属性)。你定义的自定义活动(LookupItem)具有ItemCode作为输入参数而返回ItemInfo作为输出参数。

   LookupItem类继承自CodeActivity并重写了Execute方法,在方法中创建了ItemInfo并将输入参数ItemCode赋值给新创建的ItemInfo的实例属性ItemCode。提醒一下,方法中为什么使用Context.GetValue()取得ItemCode的值?这是因为ItemCode参数由工作流自身维护的,当Execute()方法被调用时CodeActivityContext将提供流程信息的设置和获取操作。

   Exectue()方法中,我们将DescriptPrice属性设置为常量值是为了演示方便,在实际应用中,可以从数据库中查出值并赋给它们。最后程序调用了context.SetValue()方法将ItemInfo存储到输出参数中。

   F6重新生成程序。

 

使用LookupItem活动

   切换OrderWF.xaml为视图设计模式,提醒:程序编译成功后会自动将LookupItem添加到Toolbox中。见Figure 7-3.

Figure 7-3. The LookupItem activity has been added to the Toolbox

展开 Accumulate Order Items”活动,将看到如下图所示的界面(Figure 7-4.)

Figure 7-4. The initial design of the Accumulate Order Items activity

    Foreach遍历了OrderInfo.Items中的每一个item,并放置了将每个itemOrderTotal加了10$Assign活动。接下来拖动Sequence活动到Body主体部分,并将DisplayName设置为”Lookup Item”,删除Assign活动。拖动”LookupItem”自定义活动到”Lookup Item”Sequence活动主体部分,”LookupItem”属性窗口包含了这个活动定义的ItemCodeItem参数。DisplayName参数是基类CodeActivity中已经定义的。

Figure 7-5. The Properties window of the LookupItem activity

 

ItemCode属性中输入VB表达式:item.ItemCode

接下你必须定义一个变量来存储ItemInfo类的返回值,点击流程设计器左下角的【变量】按钮,在显示的变量清单中点击【创建变量】将会添加一条变量记录在清单中,名称输入对应输入ItemDetails,双击变量类型会弹出下拉框,选中下拉项中的【浏览类型】弹出类型选择框,如下图所示:

Figure 7-6. Selecting the class that defines the variable type

 

当前变量的默认作用域”Lookup Item”Seqence活动是正确的。变量定义结果如下图Figure 7-7.所示:

Figure 7-7. The definition for the ItemDetails variable

 

现在选择LookupItem活动并设置Item属性为ItemDetails。通过自定义活动”LookupItem”返回ItemInfo实例并存储到ItemDetails变量中。拖动Assign活动到LookupItem活动下方且放置在名为Lookup ItemSequence活动块中。将Assign活动的两个属性ToValue分别设置为TotalAmountTotalAmount + (item.Quantity * ItemDetails.Price)。这个表达式是计算所有订单的总金额。流程示例如下图Figure 7-8

Figure 7-8. The final Accumulate(累积) Order Items activity

 

F5运行程序,将会看图如下图所示的结果

Order Received

The item total is: $105

Item is out of stock - Item Code: 12346

The total amount is: $165

Workflow returned $165 for my order total

Press ENTER to exit

你可以按照下面所示通过手工计算来验证下结果是否正确!

 

InvokeMethod活动

InvokeMethod活动提供了除标准内置活动之外的另一种实现方式。你可以使用这种方式去回调某个类的方法。InvokeMethod活动类不需要作为工作流一部分或使用任何工作流的基类。在下面的示例项目中,您将实现一个基于各种规则为的类来计算折扣金额,工作流将回调此类来计算指定订单的折扣。

 

创建DisCount

Solution Explorer中,右击OrderProcess项目选择Add->Class将新建的类命名为OrderDiscount.cs,类的实现就像下面的代码所示:

Listing 7-2. OrderDiscount class

 

using System;

using System.Collections.Generic;

namespace OrderProcess

{

    public static class OrderDiscount

    {

        public static decimal ComputeDiscount(Order o, decimal total)

        {

            // Count the number of items ordered

            int count = 0;

            foreach (OrderItem i in o.Items)

            {

                count += i.Quantity;

            }

 

            // Determine the discount percentage

            decimal pct = 0;

            if (total > 500)

                pct = (decimal)0.20;

            if (total > 200)

                pct = (decimal)0.15;

            if (total > 100)

                pct = (decimal)0.10;

            // Calculate the discount amount

            decimal discount = total * pct;

            // Subtract a dollar for every item ordered

            discount -= (decimal)count;

            // Make sure it’??s not less than zero

            if (discount < 0)

                discount = 0;

            Console.WriteLine("Discount computed: ${0}", discount.ToString());

            return discount;

        }

    }

}

 

ComputeDiscount()方法接收Order类和total两个参数并返回本次预订的折扣金额。

 

F6重新生成程序.

 

使用InvokeMethod活动

接下来你可以使用InvokeMethod活动来执行ComputeDiscount()方法。在流程设计器中的”Check Stock”活动之前拖入InvokeMethod活动,并将DisplayName属性设置为Calculate Discount

 

指定目标对象

TargetType属性指定要将要使用回调方法的类,在下拉框中选择【浏览类型】一个Net类型选择对话框,展开OrderProcess程序集,然后选择OrderDiscount类,如Figure 7-9.图所示:

Figure 7-9. Selecting the OrderDiscount class

提示:

你可以使用两种方法来指定被回调方法的对象。如果方法是在静态类中,你可以像我上面做的哪样简单地指定TargetType属性。

如果类不是静态的则必须指定一个对象的实例,最好的方式是定义一个类类型的变量,然后在TargetObject属性中指定变量名。如果有多个实例,则需要去控制哪个实例被使用,你可以在Assign活动或自定义活动之前设置变量去执行InvokeMethod活动。如果你已经设置了TargetObject属性则不必要去指定TargetType属性值。

 

MethodName属性中设置ComputeDiscount方法名。

 

指定参数

将鼠标移到 Calculate Discount”错误指示器的上面。你将会看到如下所示的提示信息。

Figure 7-10. InvokeMethod error message

 

显示这样的错误是因为还没有定义参数。 Calculate Discount”属性窗口中点击【Parameters】右边的省略号按钮将弹出如下图所示的属性对话框:

Figure 7-11. An empty Parameters collection

 

点击【创建参数】在Direction(方向)中选择In(输入)Type(类型)中选择OrderValue()设置为OrderInfoOrderInfo是正在处理的订单类Order的变量,使用同样的方法再创建第二个输入参数TotalAmountType(类型)设置为DecimalValue()设置为TotalAmount。操作完成后我们将看到如下图Figure 7-12所示的结果:

Figure 7-12. The completed Parameters collection

 

指定结果

ComputeDiscount()方法返回decimal类型的折扣金额,您需要创建一个变量来存储返回的结果。切换工作流设计器左下角的【变量】点击【创建变量】将Name设置为Discount,变量类型设置为Decimal,并且将范围设置为Sequence。变量定义清单看起来就像下图Figure 7-13所示:

Figure 7-13. Adding a Discount variable

     选择InvokeMethod活动,在属性窗口中将Result属性设置为Discount,设置完成后InvokeMethod的属性界面如下图Figure 7-14.所示:

Figure 7-14. The completed Properties window

“Calculate Discount”活动如下图Figure 7-15.所示:

Figure 7-15. The Calculate Discount activity

 

添加折扣

最后一步从当前订单总额中减去折扣,拖动Assign活动到“Calculate Discount”活动的下方,将Assign活动的ToValue属性分别设置为TotalAmountTotalAmount Discount。设置结果如下图Figure 7-16.所示:

Figure 7-16. Partial workflow diagram

 

运行程序

F5运行程序,你将会看到如下所示的结果:

Order Received

The item total is: $105

Discount computed: $4.5

Item is out of stock - Item Code: 12346

The total amount is: $160.5

Workflow returned $160.5 for my order total

Press ENTER to exit