65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows Workflow Foundation 中的 XAML 简介

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (14投票s)

2007年4月13日

9分钟阅读

viewsIcon

147221

downloadIcon

823

Windows Workflow Foundation 教程中的第三篇文章。

引言

这是关于“Windows Workflow Foundation”介绍性系列文章的第三篇。在第一篇文章中,我们快速浏览了 Windows Workflow Foundation,并开发了一个基于“顺序工作流”的初步航班预订系统。随后,在第二篇文章中,我们探索了“状态机工作流”,并开发了一个采购订单系统。现在,我们将重点关注XAML,并学习如何在 Windows Workflow Foundation 中使用它来设计工作流。

你好,XAML!

可扩展应用程序标记语言,简称 XAML(发音为 zammel),是 Windows Framework 和 Windows Presentation Foundation 中使用的一种新的声明式语言。XAML 随 .NET Framework 3.0 推出,标志着声明式(与命令式编码相对)编程模型的到来。在 Workflow Foundation 中,可以通过代码和 XAML 来创建工作流。甚至可以实现完全基于 XAML 的解决方案,无需任何代码!这不仅为应用程序提供了无需编译的灵活性,还为非技术人员(如业务分析师)设计工作流开启了可能。 (尽管 Workflow Foundation 主要面向程序员,但全球范围内正在进行相关实验,以使其对业务分析师来说也能够可行地在此建模流程)。

XAML 与 Workflow Foundation

使用 Workflow Foundation,可以通过三种方式设计工作流:纯代码、代码/XAML 混合以及纯 XAML。部分代码/XAML 工作流是代码和 XAML 的组合。例如,典型场景是:对应用程序进行总体概览,并使用 XAML 定义工作流,然后由开发人员用代码为每个工作流活动添加技术细节。这些解决方案需要编译。纯 XAML 解决方案中的工作流以及所有条件/规则都在 XAML 中指定,并且可以在不编译的情况下托管,尽管需要“XAML 激活”才能使其正常工作。

本文将涵盖的内容

我们将使用 XAML 开发世界上最简单的顺序工作流,以“声明式”(即在 XAML 中)方式添加一些规则,然后插入一些控制台输出代码。我们将学习声明式编程模型,玩转 XAML,并了解 XAML 和代码如何集成!

让我们开始吧

向所有坚持到现在的“Alpha Blue Geeks”致敬,感谢你们的耐心,并邀请你们投入到一些真正令人兴奋的实践工作中。请在开始菜单中点击“Microsoft Visual Studio 2005”,选择“新建项目”,然后选择“Sequential Workflow Console Application”。

Screenshot - image001.jpg

默认情况下,Workflow 项目会包含一个基于代码的工作流文件,现在由于我们更想玩转 XAML,我们将删除该文件。在“解决方案资源管理器”中右键单击项目,选择“添加新项”,然后选择“Sequential Workflow with Code Separation”文件。“代码分离”表明我们正在进行一些“令人兴奋的”(即 XAML)与基础代码不同的操作。

Screenshot - image002.jpg

完成此操作后,点击“添加”,您将看到标准的空工作流设计器窗口。在这里稍作停留,让我们来探索一下我们这个“宠物项目”包含哪些文件。在“解决方案资源管理器”窗口中,有一个 MyWorkflow.xoml 文件,这个文件包含了我们的工作流 XAML。由于工作流目前是空的,如果您打开该文件,它只会包含一个头部节点。[您可以通过右键单击文件并选择“在浏览器中查看”来查看 XAML,或者,进入项目文件夹,选择 MyWorkflow.xoml 文件并在您喜欢的 XML 编辑器中打开]。MyWorkflow.xoml 目前应该看起来像这样。

<SequentialWorkflowActivity x:Class="FirstXAMLWFApplication.MyWorkflow 1"   
    Name="MyWorkflow 1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

</SequentialWorkflowActivity>

让我们用放大镜仔细看看。根元素是“Sequential Workflow Activity”;正如我们正在开发一个顺序工作流应用程序一样,这应该是合理的。

另一个选项是 StateMachineWorkflowActivity。该元素有两个重要属性;Class 和 Name,其中“Class”指定了我们工作流类的完全限定名称,“Name”就是我们工作流的“name”属性值。

为了满足我们“做些令人兴奋的事情”的渴望,让我们在工作流中添加一个 While 活动。While 活动是 Microsoft 提供的“Base Activity Library”的一部分,该库包含许多活动,这些活动可用于各种工作流,无论它们属于哪个业务领域。库中的一些活动包括:CodeIfElseDelayWebServiceInputReplicator 等。

While 活动是最简单且最常用的活动之一。几乎每个工作流都有需要迭代运行的任务;因此 While 活动,它会在某个特定条件满足之前,持续运行一个特定的活动。

我们总是可以通过在工作流设计器窗口中进行拖放来添加 While 活动,但让我们先玩玩酷炫且基础的 XAML。

打开 MyWorkFlow.xoml 并添加以下代码(粗体显示)。

<SequentialWorkflowActivity
    x:Class="FirstXAMLWFApplication. MyWorkflow" Name="MyWorkflow "
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
       <WhileActivity x:Name="whileActivity1">
       </WhileActivity>
</SequentialWorkflowActivity>

保存文件,然后切换回 VS.NET IDE 并打开工作流。它看起来会像这样

Screenshot - image003.jpg

很酷,对吧!?但是你能看到那个红色的感叹号吗?它表示我们还没有为循环指定终止条件。让我们进入代码并在工作流类中添加一个受保护的变量。代码片段

namespace FirstXAMLWFApplication
{
     public partial class MyWorkflow : SequentialWorkflowActivity
     {
         public Int32 counter;
     }
}

回到设计器窗口,在 While 活动的“Condition”属性中选择“Declarative Rule Condition”,然后单击“Condition Name”的“Ellipse”。应该会显示以下对话框。

Screenshot - image004.jpg

单击“Add”进入“Rule Condition Editor”并添加以下条件。

Screenshot - image005.jpg

我们在这里添加了一个简单的条件,它将使 While 循环一直运行,直到 counter 达到 10,届时它将终止。现在可能是时候回到我们的 XAML 文件,看看这个声明式条件是如何添加到其中的了。

<SequentialWorkflowActivity x:Class="FirstXAMLWFApplication.MyWorkflow" 
    x:Name="MyWorkflow"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
    <WhileActivity x:Name="whileActivity1">
        <WhileActivity.Condition>
            <RuleConditionReference ConditionName="Condition1" />
        </WhileActivity.Condition>
    </WhileActivity>
</SequentialWorkflowActivity>

“嗯,我看到 Condition 属性被设置为 Condition1,这是我们最近添加的条件的名称,但实际的条件语句在哪里?” 好问题!项目中有一个单独的文件名为 MyWorkflow.rules,所有规则都保存在该文件中。为了简洁起见,我没有添加该文件的摘录(尽管您始终可以从文章顶部的附件代码中下载它以详细了解)。目前,就够了,我们的声明式规则语句存在于 .rules 文件中,而条件名称则包含在 XAML 中。这再次向我们展示了使用 XAML 设计工作流的强大功能,因为我可以将一百万个规则添加到我的项目中,并通过在 XAML 中添加一行来将其与特定活动关联!并且甚至可以通过简单地更改条件的名称来稍后编辑/替换它,就是这样!

这足以让 while 活动执行了,现在让我们在其中添加一个活动。您可以将其视为循环体。这里我们将添加一个 IfElse 活动,然后在 While 活动中的每个 IfElse 分支中添加一个 Code 活动。这次我们将使用 VS IDE 的强大功能,只需将活动拖放到工作流设计器中即可。添加这些新活动后,工作流的最终形状将如下所示

Screenshot - image006.jpg

正如我们所见,IfElse 活动有两个分支。当 If 条件为真时执行一个分支,当 else 条件为真时执行另一个分支。我们将为每个分支分配适当的条件,但现在,让我们看看我们的 XAML 文件,看看工作流中的这个更改是如何翻译到其中的。

<SequentialWorkflowActivity x:Class="FirstXAMLWFApplication.MyWorkflow" 
    x:Name="MyWorkflow" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
    <WhileActivity x:Name="whileActivity1">
        <WhileActivity.Condition>
            <RuleConditionReference ConditionName="Condition1"/>
        </WhileActivity.Condition>
     <IfElseActivity x:Name="ifElseActivity1">
            <IfElseBranchActivity x:Name="ifElseBranchActivity1">
                <CodeActivity x:Name="codeActivity1"
                    ExecuteCode="codeActivity1_ExecuteCode" />
            </IfElseBranchActivity>
            <IfElseBranchActivity x:Name="ifElseBranchActivity2">
                <CodeActivity x:Name="codeActivity2"
                    ExecuteCode="codeActivity2_ExecuteCode" />
            </IfElseBranchActivity>
        </IfElseActivity>
    </WhileActivity>
</SequentialWorkflowActivity>

简单且结构化?你打赌!粗体语句显示了我们新的 IfElseCode 活动。现在,我们在 IfElse 活动的每个分支中添加简单的条件。为了简单起见,我们将简单地检查计数器是偶数还是奇数,并根据此条件检查,将每个控制发送到每个分支。我们将添加这两个规则,并使用与 While 活动相同的机制(从属性窗口 -> 选择条件 -> 规则条件编辑器)将它们分配给每个分支。我们每个分支的条件将是

this.counter
% 2 == 0  // for even
this.counter
% 2 != 0  // for odd

最后,我们的“选择条件”看起来像这样

Screenshot - image007.jpg

嘿!我说过我们**会**写一些代码吗?是的,我说了,现在是时候这样做了。选择“CodeActivity1”,在“Properties”窗口中单击“Generate Handlers”,然后深入其处理程序代码。在其中添加以下代码。我们只是在控制台显示消息,宣布这是一个偶数,并递增了我们的计数器变量。

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
    Console.WriteLine("Hello! " + Convert.ToString(counter) + 
        " is an even number!");
    counter++;
}
同样,为“CodeActivity2”添加以下代码。
private void codeActivity2_ExecuteCode(object sender, EventArgs e)
{
    Console.WriteLine("Hello! " + Convert.ToString(counter) + 
        " is an odd number!");
    counter++;
}

耶!就这样。我们完成了工作流。让我们回顾一下我们所做的。

  1. 我们使用 XAML 添加了一个 while 活动。
  2. 我们以“声明式”方式为 while 活动添加了一个条件。该条件仅检查 counter 字段是否小于 10
  3. 然后我们将在 While 活动中拖放 IfElseCodeActivity
  4. IfElse 活动的每个分支中添加了适当的条件来检查它是偶数/奇数
  5. Code 活动处理程序中添加了代码,用于在控制台显示和递增 counter 字段。

Workflow runtime 需要一个宿主来运行工作流。我们的宿主将是一个简单的控制台应用程序。我们的项目包含 Progam.cs,在这里我们的工作流运行时将实际启动。将创建、执行工作流实例,然后关闭运行时。这没有什么复杂的;只是 VS IDE 为我们生成的相当简单的代码

static void Main(string[] args)
{
    using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
    {
        AutoResetEvent waitHandle = new AutoResetEvent(false);
        workflowRuntime.WorkflowCompleted += delegate(object sender,              
            WorkflowCompletedEventArgs e) {waitHandle.Set();};
        workflowRuntime.WorkflowTerminated += delegate(object sender,
            WorkflowTerminatedEventArgs e)
        {
            Console.WriteLine(e.Exception.Message);
            waitHandle.Set();
        };

        WorkflowInstance instance = workflowRuntime.CreateWorkflow(
            typeof(FirstXAMLWFApplication.MyWorkflow));
        instance.Start();

        waitHandle.WaitOne();
        Console.ReadKey();
    }
}

创建了一个新的运行时对象。为工作流的“Completed”和“Terminated”状态提供了两个事件处理程序。然后调用“Create Workflow”来获取我们工作流的一个实例,并调用“Start”来启动它。运行时引擎将异步执行我们的工作流,因此,我们需要在 AutoResetEvent 对象上阻塞我们的线程,并等待工作流完成(否则,在我们看到控制台窗口中的内容之前,它就会关闭,程序也会退出!)。现在,使用 AutoResetEvent 意味着线程将被阻塞,直到在完成事件处理程序中“设置”它。

就这样,伙计们。点击“Run”观看表演。好吧,我们的输出可能不会有多少美学上的吸引力,但它应该能让我们对 XAML 有一个很好的认识。以及为什么以及如何将其与 Workflow Foundation 一起使用。

我们的输出窗口看起来像这样

Screenshot - image008.jpg

在 Workflow Foundation 中,我们还能用 XAML 做些什么?

很多!我们甚至可以设计完全基于 XAML 的工作流,而且我们甚至不需要编译它们。也就是说,一个人可以使用 XAML 设计一个工作流(除了 Visual Studio 之外的任何工具也可以使用,毕竟这一切都是关于创建/修改一个类似 XML 的文档),然后部署它来运行。“XAML 激活”被用于替代编译来启动工作流。这超出了本文的范围,我们选择了一种折衷的方法,即同时使用 XAML 和代码(声明式和命令式编程模型),因为工作流在很大程度上就是这样设计的和实现的。

在哪里可以找到更多信息

我最喜欢的书籍/链接与我之前文章中指定的相同。

© . All rights reserved.