Поделиться через


Разработка рабочих процессов с помощью императивного кода

Данный раздел относится к версии Windows Workflow Foundation 4.

Определение рабочего процесса представляет собой дерево настроенных объектов действий. Это дерево действий можно определить многими способами, включая редактирование XAML вручную и использование конструктора рабочих процессов для создания XAML. Но использование XAML не является обязательным. Определения рабочих процессов могут быть также созданы вручную. В этом разделе представлены общие сведения о создании определений рабочих процессов с помощью кода.

Создание определений рабочих процессов

Определение рабочего процесса можно создать путем создания экземпляра типа действия и настройки свойств объекта действия. Для действий, которые не содержат дочерних действий, определение можно создать программно с помощью нескольких строк кода.

Activity wf = new WriteLine
{
    Text = "Hello World."
};

WorkflowInvoker.Invoke(wf);
Ee358749.note(ru-ru,VS.100).gifПримечание
В примерах в этом разделе используется 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);

Дополнительные сведения динамических действиях см. в разделе Создание действия в среде выполнения с динамическим действием.