Använda aktivitetsdelegater

Aktivitetsdelegater låter aktivitetsförfattare exponera återuppringningar med specifika signaturer, för vilka användarna av aktiviteten kan ange aktivitetsbaserade hanterare. Två typer av aktivitetsdelegater är tillgängliga: ActivityAction<T> används för att definiera aktivitetsdelegater som inte har ett returvärde och ActivityFunc<TResult> används för att definiera aktivitetsdelegater som har ett returvärde.

Aktivitetsdelegater är användbara i scenarier där en barnaktivitet måste ha en specifik signatur. En aktivitet kan till exempel While innehålla alla typer av underordnade aktiviteter utan begränsningar, men en aktivitets ForEach<T> brödtext är en ActivityAction<T>, och den underordnade aktivitet som slutligen körs av ForEach<T> måste ha en InArgument<T> som är samma typ av medlemmar i samlingen som ForEach<T> räknas upp.

Att använda ActivityAction

Flera .NET Framework 4.6.1-aktiviteter använder aktivitetsåtgärder, till exempel Catch aktiviteten och ForEach<T> aktiviteten. I varje fall representerar aktivitetsåtgärden en plats där arbetsflödesförfattaren anger en aktivitet som ger önskat beteende när ett arbetsflöde skapas med någon av dessa aktiviteter. I följande exempel används en ForEach<T> aktivitet för att visa text i konsolfönstret. Kroppen av ForEach<T> anges genom att använda en ActivityAction<T> som matchar typen av ForEach<T>, vilken är sträng. Aktiviteten WriteLine som anges i Handler har sitt Text argument bundet till strängvärdena i samlingen som ForEach<T> aktiviteten itererar.

DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();

Activity wf = new ForEach<string>
{
    Body = new ActivityAction<string>
    {
        Argument = actionArgument,
        Handler = new WriteLine
        {
            Text = new InArgument<string>(actionArgument)
        }
    }
};

List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");

Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);

WorkflowInvoker.Invoke(wf, inputs);

ActionArgument används för att skicka de enskilda objekten i samlingen till WriteLine. När arbetsflödet anropas visas följande utdata i konsolen.

HelloWorld.

Exemplen i det här avsnittet använder initieringssyntax för objekt. Initieringssyntax för objekt kan vara ett användbart sätt att skapa arbetsflödesdefinitioner i kod eftersom det ger en hierarkisk vy över aktiviteterna i arbetsflödet och visar relationen mellan aktiviteterna. Det finns inget krav på att använda initieringssyntax för objekt när du programmatiskt skapar arbetsflöden. Följande exempel är funktionellt likvärdigt med föregående exempel.

DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();

WriteLine output = new WriteLine();
output.Text = new InArgument<string>(actionArgument);

ActivityAction<string> body = new ActivityAction<string>();
body.Argument = actionArgument;
body.Handler = output;

ForEach<string> wf = new ForEach<string>();
wf.Body = body;

List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");

Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);

WorkflowInvoker.Invoke(wf, inputs);

Mer information om objektinitierare finns i How to: Initialize Objects without Calling a Constructor (C# Programming Guide) and How to: Declare an Object by Using an Object Initializer (Visual Basic).

I följande exempel används en TryCatch aktivitet i ett arbetsflöde. En ApplicationException genereras av arbetsflödet och hanteras av en Catch<TException> aktivitet. Hanteraren för Catch<TException> aktivitetens aktivitetsåtgärd är en WriteLine aktivitet och undantagsinformationen skickas till den med hjälp av exDelegateInArgument<T>.

DelegateInArgument<ApplicationException> ex = new DelegateInArgument<ApplicationException>()
{
    Name = "ex"
};

Activity wf = new TryCatch
{
    Try = new Throw()
    {
        Exception = new InArgument<Exception>((env) => new ApplicationException("An ApplicationException was thrown."))
    },
    Catches =
    {
        new Catch<ApplicationException>
        {
            Action = new ActivityAction<ApplicationException>
            {
                Argument = ex,
                Handler = new WriteLine()
                {
                    Text = new InArgument<string>((env) => ex.Get(env).Message)
                }
            }
        }
    },
    Finally = new WriteLine()
    {
        Text = "Executing in Finally."
    }
};

När du skapar en anpassad aktivitet som definierar en ActivityAction<T> använder du en InvokeAction<T> för att modellera hur man anropar den ActivityAction<T>. I det här exemplet definieras en anpassad WriteLineWithNotification aktivitet. Den här aktiviteten består av en Sequence som innehåller en WriteLine aktivitet följt av en InvokeAction<T> som anropar ett ActivityAction<T> som tar ett strängargument.

public class WriteLineWithNotification : Activity
{
    public InArgument<string> Text { get; set; }
    public ActivityAction<string> TextProcessedAction { get; set; }

    public WriteLineWithNotification()
    {
        this.Implementation = () => new Sequence
        {
            Activities =
            {
                new WriteLine
                {
                    Text = new InArgument<string>((env) => Text.Get(env))
                },
                new InvokeAction<string>
                {
                    Action = TextProcessedAction,
                    Argument = new InArgument<string>((env) => Text.Get(env))
                }
            }
        };
    }
}

När ett arbetsflöde skapas med hjälp WriteLineWithNotification av aktiviteten anger arbetsflödesförfattaren önskad anpassad logik i aktivitetsåtgärdens Handler. I det här exemplet skapas ett arbetsflöde som använder WriteLineWithNotification aktiviteten och en WriteLine aktivitet används som Handler.

// Create and invoke the workflow without specifying any activity action
// for TextProcessed.
Activity wf = new WriteLineWithNotification
{
    Text = "Hello World."
};

WorkflowInvoker.Invoke(wf);

// Output:
// Hello World.

// Create and Invoke the workflow with specifying an activity action
// for TextProcessed.
DelegateInArgument<string> msg = new DelegateInArgument<string>();
Activity wf2 = new WriteLineWithNotification
{
    Text = "Hello World with activity action.",
    TextProcessedAction = new ActivityAction<string>
    {
        Argument = msg,
        Handler = new WriteLine
        {
            Text = new InArgument<string>((env) => "Handler of: " + msg.Get(env))
        }
    }
};

// Invoke the workflow with an activity action specified
WorkflowInvoker.Invoke(wf2);

// Output:
// Hello World with activity action.
// Handler of: Hello World with activity action.

Det finns flera allmänna versioner som tillhandahålls av InvokeAction<T> och ActivityAction<T> för att skicka ett eller flera argument.

Använda ActivityFunc

ActivityAction<T> är användbart när det inte finns något resultatvärde från aktiviteten och ActivityFunc<TResult> används när ett resultatvärde returneras. När du skapar en anpassad aktivitet som definierar en ActivityFunc<TResult> använder du en InvokeFunc<TResult> för att modellera hur man anropar den ActivityFunc<TResult>. I följande exempel definieras en WriteFillerText aktivitet. För att ange fyllnadstexten anges en InvokeFunc<TResult> som tar ett heltalsargument och har ett strängresultat. När fyllnadstexten har hämtats visas den för konsolen med hjälp av en WriteLine aktivitet.

public class WriteFillerText : Activity
{
    public ActivityFunc<int, string> GetText { get; set; }
    public InArgument<int> Quantity { get; set; }

    Variable<string> text = new Variable<string>
    {
        Name = "Text"
    };

    public WriteFillerText()
    {
        this.Implementation = () => new Sequence
        {
            Variables =
            {
                text
            },
            Activities =
            {
                new InvokeFunc<int, string>
                {
                    Func = GetText,
                    Argument = new InArgument<int>((env) => Quantity.Get(env)),
                    Result = new OutArgument<string>(text)
                },
                new WriteLine
                {
                    Text = new InArgument<string>(text)
                }
            }
        };
    }
}

Om du vill ange texten måste en aktivitet användas som tar ett int argument och har ett strängresultat. Det här exemplet visar en TextGenerator aktivitet som uppfyller dessa krav.

public class TextGenerator : CodeActivity<string>
{
    public InArgument<int> Quantity { get; set; }
    public InArgument<string> Text { get; set; }

    protected override string Execute(CodeActivityContext context)
    {
        // Provide a quantity of Random Text
        int q = Quantity.Get(context);
        if (q < 1)
        {
            q = 1;
        }

        string text = Text.Get(context) + " ";
        StringBuilder sb = new StringBuilder(text.Length * q);
        for (int i = 0; i < q; i++)
        {
            sb.Append(text);
        }

        return sb.ToString();
    }
}

Om du vill använda -aktiviteten med -aktiviteten, anger du den som .

DelegateInArgument<int> actionArgument = new DelegateInArgument<int>();

Activity wf = new WriteFillerText
{
    Quantity = 5,
    GetText = new ActivityFunc<int, string>
    {
        Argument = actionArgument,
        Handler = new TextGenerator
        {
            Quantity = new InArgument<int>(actionArgument),
            Text = "Hello World."
        }
    }
};

WorkflowInvoker.Invoke(wf);