饭饭TXT > 学习管理 > 《Visual Studio 2010 高级编程(英文出书版)》作者:Nick Randolph/等【完结】 > [Visual.Studio.2010.高级编程].Professional.Visual.Studio.2010.txt

第 106 页

作者:Nick Randolph/等 当前章节:15460 字 更新时间:2026-6-18 14:51

picture of the entire diagram to the clipboard, whereas the Save as Image menu item shows a dialog

box enabling you to save the diagram to your choice of a JPEG, PNG, GIF, or XPS document. You

can then paste the diagram into your document or presentation (if you copied it to the clipboard), or

import it if you had saved it to disk.

creatinG a workflow

This section walks through the process of creating a very simple workflow that demonstrates a

number of the features of WF. For this example, you will simply be writing output to the console

window and receiving input from the user, but doing so in a workflow rather than regular code.

Creating a Workflow .

713

designing a workflow

The first thing you want to do is to drop a control flow activity onto the designer that will schedule the

execution of the activities that it contains. For this example, you will use a Sequence activity for this

purpose. You will find the Sequence activity under the Control Flow category in the Toolbox. Drag

and drop it into your SimpleProcessWorkflow workflow, as demonstrated in Figure 32-8.

fiGure 32-8

At this point, it would be useful to give it a meaningful name — click in its header and change it to

SimpleProcessSequence. You can also simply select the activity and set its DisplayName property in

the Properties tool window.

For this initial example, you’ll get the workflow to execute a do/while loop that will write a message to

the console five times. To do this, you then need to drop a DoWhile activity into the Sequence activity

from the Control Flow category in the Toolbox. Once you’ve done that, you will find that both the

new activity and the Sequence activity are now displaying as invalid (a red icon with an exclamation

mark appears in the right side of the headers of both activities). This is because an expression needs to

be assigned to the condition of the DoWhile activity before it can be considered valid.

If you attempt to compile the application that has an invalid activity, it will still

compile but when you try to run it you will receive a run time error. You can,

however, see a list of all the validation errors in a workflow as errors in the Error

List tool window.

Because you want to place more than one activity in the DoWhile activity, add a Sequence activity

as its child. Call this sequence WriteHelloWorldSequence.

714 .

chaPter 32 WindoWS WorkFloW FoundATion (WF)

Now find the WriteLine activity in the Toolbox (under the Primitives category), and drag and drop that

into the WriteHelloWorldSequence activity. To make it write Hello World to the output each time it’s

executed, set its Text argument to “Hello World“ (with the argument accepting an expression and being

a string value that you are assigning, you need to assign it as a literal value by enclosing it in quotes).

So that the output can be seen more easily, drop a Delay activity (from the Primitives category in

the Toolbox) into the WriteHelloWorldSequence activity, following the WriteLine activity. The

Delay activity’s Duration argument accepts a TimeSpan type — you’ll use an expression to specify

its value as 200 milliseconds because it’s more readable than the literal value:

TimeSpan.FromMilliseconds(200)

To control the number of times this loop will execute, add a variable called Counter to the

SimpleProcessSequence activity (which will be available to all the activities in the sequence). Select

the SimpleProcessSequence activity and pop up the Variables pane. Click where it says Create

Variable, enter Counter as its name, a type of Int32, and a default value of 0.

Back in the DoWhile activity, you can now specify the following expression as its condition:

Counter < 5

The final step is to actually increment the Counter variable. Add an Assign activity (from the

Primitives category in the Toolbox) to the sequence (following the Delay activity), setting its To

argument to Counter, and its Value argument to Counter + 1.

Your simple workflow is now complete, and should look like Figure 32-9.

fiGure 32-9

Creating a Workflow .

715

Now you can run your application, which

will execute the workflow with the results

shown in Figure 32-10.

writing code activities

Now create a custom activity whose work

is defined in code to get input from the

user. Add a new item to your project, select

the Code Activity item template from the

Workflow category in the Add New Item

dialog (as shown in Figure 32-11), and call it

UserInput.

fiGure 32-10

fiGure 32-11

This creates a class that inherits from System.Activities.CodeActivity, and overrides the

Execute method into which you can write the code that this activity will execute. It also includes

a sample input argument called Text (defined as a property on the class), which you can delete

because this activity won’t require any inputs (also delete the line of code in the Execute method

that retrieves its value).

This activity will obtain input from the user that other activities in the workflow can use. You can

return the value either as an output argument or as a return value. Either way is acceptable, so for

this example return the value.

To return a value, instead of inheriting from the CodeActivity class you will need to inherit from

its generic version instead (into which you pass the type that the activity will return). Change the

class to inherit from the generic CodeActivity class, passing in the type of the return value. Change

the Execute method to return a type instead of void (C# developers), or to a function that returns

716 .

chaPter 32 WindoWS WorkFloW FoundATion (WF)

a type (VB developers). Then it’s simply a case of returning the value returned from the Console

.ReadLine() function in the Execute method:

Vb

Public NotInheritable Class UserInput

Inherits CodeActivity(Of String)

Protected Overrides Function Execute(ByVal context As CodeActivityContext) _

As String

Return Console.ReadLine()

End Function

End Class

c#

public sealed class UserInput : CodeActivity<string>

{

protected override string Execute(CodeActivityContext context)

{

return Console.ReadLine();

}

}

If you switch back now to the workflow in the designer, you will find that

the activity is nowhere to be found in the Toolbox. However, once you

compile your project, it will appear in the Toolbox, under the category with

the same name as your project, as shown in Figure 32-12.

Drop the activity from the Toolbox into your workflow, in the main

SimpleProcessSequence sequence activity after the DoWhile activity. You

will note that there is no nice designer user interface for the activity (just a

simple block), but you could design one by creating an activity designer for

it. However a discussion of this is beyond the scope of this chapter.

When you select it, the Properties tool window will have a property called Result, in which an

expression to work with the return value of the Execute method in the activity can be specified.

What you want to do is assign the return value to a variable, which activities following it in the

sequence can use. Create a new variable in the Variables pane called UserInputValue with a type of

String. In the Properties tool window, you can now simply set UserInputValue as the expression

for the Result property, which will assign the return value from the activity to the UserInputValue

variable. You can prove this works by adding a WriteLine activity following the UserInput activity

that then writes the value of this variable back out to the console.

executing a workflow

If you inspect the Main method (the entry point of the application) in the Program.cs file (for C#

developers) or Module1.vb (for VB developers) you will find the code used to execute the workflow:

Vb

WorkflowInvoker.Invoke(New SimpleProcessWorkflow())

fiGure 32-12

Creating a Workflow .

717

c#

WorkflowInvoker.Invoke(new SimpleProcessWorkflow());

This is making use of the WorkflowInvoker class to invoke the workflow, which, as described

earlier in this chapter, has no control over the actual execution of the workflow other than simply

initiating its execution.

If you want more control over the execution of a workflow, however (such as if you need to resume

execution from a bookmark, or persist/unload a workflow), you will need to turn to the

WorkflowApplication class to invoke your workflow instead. Basic use of the WorkflowApplication

class to invoke a workflow and handle its Complete event is as follows:

Vb

Dim syncEvent As New AutoResetEvent(False)

Dim app As New WorkflowApplication(New SimpleProcessWorkflow())

app.Completed = Function(args)

Console.WriteLine("Workflow instance has completed!")

Thread.Sleep(1000)

syncEvent.Set()

Return Nothing

End Function

app.Run()

syncEvent.WaitOne()

c#

AutoResetEvent syncEvent = new AutoResetEvent(false);

WorkflowApplication app = new WorkflowApplication(new SimpleProcessWorkflow());

app.Completed = (e) = >

{

Console.WriteLine("Workflow instance has completed!");

Thread.Sleep(1000);

syncEvent.Set();

};

app.Run();

syncEvent.WaitOne();

Note that you will need to add an Imports/using statement to the System

.Threading namespace at the top of the file for the code snippets above to work.

This code assigns a delegate that will be run when the workflow has completed executing. Because

the Run method returns immediately, you will wait for the workflow to complete executing before

continuing (and exiting the application) using the WaitOne method on a AutoResetEvent, which is

notified in the Completed handler that it can enable the thread execution to continue.

718 . chaPter 32 WindoWS WorkFloW FoundATion (WF)

Executing a workfl ow via the WorkflowApplication class actually invokes it on a background

thread, with the Run method returning immediately. The host can attach event handlers to various

events raised by the WorkflowApplication class (such as when a workfl ow instance has completed, is

idle, thrown an unhandled exception, and so on), and also gains the ability to abort/cancel/terminate a

workfl ow instance, load one from a instance store, persist it, unload it, and resume from a bookmark.

You can pass input arguments into a workfl ow, and obtain output argument values from it. Input

arguments are exposed as properties from your workfl ow class, so assign values to these before

invoking the workfl ow. Output arguments are returned in a dictionary (which is the return value of

the WorkflowInvoker.Invoke method), each having a string key with the name of the argument,

and a corresponding object value that you can cast to the appropriate type.

As previously noted, workfl ows/activities are XAML fi les. By default, the XAML fi le is compiled

into the application (as a resource), but what if you want to take advantage of the fact that you

can reconfi gure a workfl ow without recompiling the application? In that case, you would have

to have the XAML fi le as a content fi le in your project instead, and dynamically load it into your

application from fi le. This is where the ActivityXamlServices class is useful. Load the XAML fi le

as an activity using the ActivityXamlServices class, and then invoke (that is, execute) the activity

that it returns with the WorkflowInvoker or WorkflowApplication class:

Vb

Dim activity As Activity = ActivityXamlServices.Load("SimpleProcessWorkflow.xaml")

WorkflowInvoker.Invoke(activity)

c#

Activity activity = ActivityXamlServices.Load("SimpleProcessWorkflow.xaml");

WorkflowInvoker.Invoke(activity);

Although we are referring to “ events ” here, you ’ ll note from the code snippets

that they aren ’ t events at all. Instead, they are properties to which you can

assign delegates. However, for the purposes of simplifying their description we ’ ll

continue to refer to them as events.

Loading and executing a workfl ow from a fi le becomes a little more complicated

when it uses custom activities (such as the UserInput activity), because the run

time will need a reference to the assemblies containing those custom activities so it

can use them. However, going into this further is beyond the scope of this chapter.

debugging workfl ows

In addition to having a rich designer support for building workfl ows, WF also includes debugging

capabilities. To defi ne a breakpoint in a workfl ow, simply select the activity and press F9, or select

Hosting the Workflow Designer .

719

Breakpoint . Insert Breakpoint from the

right-click context menu. Figure 32-13

demonstrates what an activity looks like

when it has a breakpoint set on it (on the

left), and how the activity is highlighted when fiGure 32-13

stepping through the workflow and it is the

current execution item (on the right).

As in a normal debugging session, in a workflow you step through code using shortcut keys.

Pressing F10 steps through the workflow, and pressing F11 steps into the current activity. You can

view the values of variables currently in scope in the Locals tool window.

Of course, your custom code activities can be debugged as normal by setting breakpoints in the

code editor and stepping through the code.

testing workflows

Having a well - defined testing framework is extremely important in business applications, with

it especially vital that the underlying business logic for the application is well covered with tests.

Therefore, it is essential with your workflow being at the core of your business logic that it

should be testable too. Luckily, this is indeed possible, and you can use your favorite unit testing

framework — going so far as to use Test Driven Development (TDD) practices if you want. As

discussed in the “ Executing a Workflow ” section, by using the WorkflowInvoker.Invoke method to

execute your workflow, you can pass input argument values into the workflow and obtain the resulting

output argument values (in a dictionary). Therefore, testing your workflow is as easy as supplying

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页