Разработка рабочих процессов с помощью императивного кода
Данный раздел относится к версии Windows Workflow Foundation 4.
Определение рабочего процесса представляет собой дерево настроенных объектов действий. Это дерево действий можно определить многими способами, включая редактирование XAML вручную и использование конструктора рабочих процессов для создания XAML. Но использование XAML не является обязательным. Определения рабочих процессов могут быть также созданы вручную. В этом разделе представлены общие сведения о создании определений рабочих процессов с помощью кода.
Создание определений рабочих процессов
Определение рабочего процесса можно создать путем создания экземпляра типа действия и настройки свойств объекта действия. Для действий, которые не содержат дочерних действий, определение можно создать программно с помощью нескольких строк кода.
Activity wf = new WriteLine
{
Text = "Hello World."
};
WorkflowInvoker.Invoke(wf);
![]() |
---|
В примерах в этом разделе используется WorkflowInvoker для запуска образцов рабочих процессов. Дополнительные сведения вызове рабочих процессов, передаче аргументов и различных возможных вариантах размещения см. в разделе Использование WorkflowInvoker и WorkflowApplication. |
В этом примере создается рабочий процесс, состоящий из одного действия WriteLine. Задается аргумент Text действия WriteLine и выполняется вызов рабочего процесса. Если в действии содержатся дочерние действия, то используется аналогичный метод построения. В следующем примере используется действие Sequence, которое содержит два действия WriteLine.
Activity wf = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Hello"
},
new WriteLine
{
Text = "World."
}
}
};
WorkflowInvoker.Invoke(wf);
Использование инициализаторов объектов
В примерах в этом разделе используется синтаксис инициализации объектов. Синтаксис инициализации объектов можно использовать для создания определений рабочих процессов в коде, поскольку он обеспечивает иерархическое представление действий в рабочем процессе и показывает связи между действиями. При программном создании рабочих процессов нет необходимости использовать синтаксис инициализации объектов. Следующий пример функционально эквивалентен предыдущему примеру.
WriteLine hello = new WriteLine();
hello.Text = "Hello";
WriteLine world = new WriteLine();
world.Text = "World";
Sequence wf = new Sequence();
wf.Activities.Add(hello);
wf.Activities.Add(world);
WorkflowInvoker.Invoke(wf);
Дополнительные сведения об инициализаторах объектов см. в разделах Практическое руководство. Инициализация объектов без вызова конструктора (Руководство по программированию на C#) и Как объявить объект с помощью инициализатора объектов.
Работа с переменными, литеральными значениями и выражениями
При создании определения рабочего процесса с помощью кода необходимо помнить, какая часть кода выполняется как часть создания определения рабочего процесса и какая часть кода выполняется как часть выполнения экземпляра рабочего процесса. Например, следующий рабочий процесс должен создавать случайное число и записывать его в консоль.
Variable<int> n = new Variable<int>
{
Name = "n"
};
Activity wf = new Sequence
{
Variables = { n },
Activities =
{
new Assign<int>
{
To = n,
Value = new Random().Next(1, 101)
},
new WriteLine
{
Text = new InArgument<string>((env) => "The number is " + n.Get(env))
}
}
};
После выполнения кода определения рабочего процесса происходит вызов Random.Next
и результат сохраняется в определении рабочего процесса как литеральное значение. Можно вызвать несколько экземпляров этого рабочего процесса, при этом все они отобразят одно и то же число. Чтобы обеспечить создание случайного числа во время выполнения рабочего процесса, необходимо использовать выражение, которое вычисляется при каждом запуске рабочего процесса.
new Assign<int>
{
To = n,
Value = new VisualBasicValue<int>("New Random().Next(1, 101)")
}
VisualBasicValue представляет выражение в синтаксисе Visual Basic, которое может быть использовано в качестве правостороннего значения в выражении. Оценка этого выражения будет выполняться при каждом выполнении содержащегося действия. Результат выражения назначается переменной рабочего процесса n
, и эти результаты используются следующим действием в рабочем процессе. Для получения доступа к значению переменной рабочего процесса n
во время выполнения необходим контекст ActivityContext. Доступ может быть получен с помощью следующего лямбда-выражения.
new WriteLine
{
Text = new InArgument<string>((env) => "The number is " + n.Get(env))
}
Лямбда-выражения не могут быть сериализованы в формат XAML. Чтобы обеспечить совместимость этого выражения с XAML, используйте ExpressionServices и Convert, как показано в следующем примере.
new WriteLine
{
//Text = new InArgument<string>((env) => "The number is " + n.Get(env))
Text = ExpressionServices.Convert((env) => "The number is " + n.Get(env))
}
Можно также использовать VisualBasicValue.
new WriteLine
{
//Text = new InArgument<string>((env) => "The number is " + n.Get(env))
//Text = ExpressionServices.Convert((env) => "The number is " + n.Get(env))
Text = new VisualBasicValue<string>("\"The number is \" + n.ToString()")
}
Дополнительные сведения выражениях см. в разделе Выражения.
Аргументы и динамические действия
Определение рабочего процесса создается в коде путем сборки действий в дерево действий и настройки всех свойств и аргументов. Для существующих аргументов можно выполнить привязку, но новые аргументы нельзя добавить к действиям. Сюда относятся аргументы рабочего процесса, передаваемые корневому действию. В императивном коде аргументы рабочего процесса указываются как свойства для нового CLR-типа, а в XAML они объявляются с помощью x:Class и x:Member. Поскольку при создании определения рабочего процесса как дерева объектов, содержащихся в памяти, не создается нового CLR-типа, аргументы не могут быть добавлены. Однако аргументы могут быть добавлены к DynamicActivity. В этом примере создается действие DynamicActivity, которое принимает и складывает два целочисленных аргумента и возвращает результат. Для каждого аргумента создается свойство DynamicActivityProperty, результат операции присваивается аргументу Result действия DynamicActivity.
InArgument<int> Operand1 = new InArgument<int>();
InArgument<int> Operand2 = new InArgument<int>();
DynamicActivity<int> wf = new DynamicActivity<int>
{
Properties =
{
new DynamicActivityProperty
{
Name = "Operand1",
Type = typeof(InArgument<int>),
Value = Operand1
},
new DynamicActivityProperty
{
Name = "Operand2",
Type = typeof(InArgument<int>),
Value = Operand2
}
},
Implementation = () => new Sequence
{
Activities =
{
new Assign<int>
{
To = new ArgumentReference<int> { ArgumentName = "Result" },
Value = new InArgument<int>((env) => Operand1.Get(env) + Operand2.Get(env))
}
}
}
};
Dictionary<string, object> wfParams = new Dictionary<string, object>
{
{ "Operand1", 25 },
{ "Operand2", 15 }
};
int result = WorkflowInvoker.Invoke(wf, wfParams);
Console.WriteLine(result);
Дополнительные сведения динамических действиях см. в разделе Создание действия в среде выполнения с динамическим действием.