Dela via


Använda aktivitetsdelegater

Aktivitetsdelegater gör det möjligt för aktivitetsförfattare att exponera motringningar med specifika signaturer, för vilka användare av aktiviteten kan tillhandahålla 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 underordnad aktivitet måste begränsas till att ha en viss 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.

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. Brödtexten ForEach<T> i anges med hjälp av en ActivityAction<T> som matchar typen som ForEach<T> ä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 flöda 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 anropet av 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 av InvokeAction<T> och ActivityAction<T> tillhandahålls 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 anropet av 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 TextGenerator aktiviteten med WriteFillerText aktiviteten anger du den Handlersom .

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);