Как да подадете параметри към CodeActivity в кодова последователност NativeActivity

Опитвам се да накарам работните потоци на Windows да работят и съм малко объркан.

Накарах един работен поток да работи, но сега се опитвам да направя нещо малко по-сложно: стартирам работен поток, където всяка дейност сама по себе си съдържа работен поток. (Изобразете нещо подобно на основната програма, която стартира дейностите „Вход, логика и изход“, а след това всяка от тях има допълнителни дейности като „подкана към потребителя, получаване на вход и т.н.“)

Накарах го да работи добре с примера от тук (http://msdn.microsoft.com/en-us/magazine/gg535667.aspx), когато не предавам никакви параметри от основната програма към дейностите. Въпросът ми е как точно работят „Променливи“ и „метаданни.SetVariablesCollection“ в NativeActivity и как да получа параметрите на дейностите на ниско ниво?

Това е, което опитвам в момента:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.Collections.ObjectModel;
using System.Activities.Statements;

namespace Project1
{
    internal class MainProgram
    {
        internal static void Main(string[] args)
        {
            try
            {
                var act = new SimpleSequence();

                act.Activities.Add((Activity)(new WriteSomeText()));
                act.Activities.Add((Activity)(new WriteSomeText()));
                act.Activities.Add((Activity)(new WriteSomeText()));

                act.Variables.Add(new Variable<string> ("stringArg", "TEXT"));

                WorkflowInvoker.Invoke(act);
            }
            catch (Exception ex)
            {
                System.Console.WriteLine("EXCEPTION: {0}", ex);
            }
        }

        public class WriteSomeText : CodeActivity
        {
            [RequiredArgument]
            public InArgument<string> stringArg { get; set; }

            protected override void Execute(CodeActivityContext context)
            {
                string output = context.GetValue(stringArg);
                System.Console.WriteLine(output);
            }

        }

        public class SimpleSequence : NativeActivity
        {
            Collection<Activity> activities;
            Collection<Variable> variables;

            Variable<int> current = new Variable<int> { Default = 0 };

            public Collection<Activity> Activities
            {
                get
                {
                    if (this.activities == null)
                        this.activities = new Collection<Activity>();

                    return this.activities;
                }
                set
                {
                    this.activities = value;
                }
            }

            public Collection<Variable> Variables
            {
                get
                {
                    if (this.variables == null)
                        this.variables = new Collection<Variable>();

                    return this.variables;
                }
                set
                {
                    this.variables = value;
                }
            }

            protected override void CacheMetadata(NativeActivityMetadata metadata)
            {
                metadata.SetChildrenCollection(this.activities);
                metadata.SetVariablesCollection(this.variables);
                metadata.AddImplementationVariable(this.current);
            }

            protected override void Execute(NativeActivityContext context)
            {
                if (this.Activities.Count > 0)
                    context.ScheduleActivity(this.Activities[0], onChildComplete);
            }

            void onChildComplete(NativeActivityContext context, ActivityInstance completed)
            {
                int currentExecutingActivity = this.current.Get(context);
                int next = currentExecutingActivity + 1;

                if (next < this.Activities.Count)
                {
                    context.ScheduleActivity(this.Activities[next], this.onChildComplete);

                    this.current.Set(context, next);
                }
            }
        }
    }
}

Това завършва със следното изключение:

EXCEPTION: System.Activities.InvalidWorkflowException: The following errors were encountered while processing the workflow tree:
'WriteSomeText': Value for a required activity argument 'stringArg' was not supplied.
'WriteSomeText': Value for a required activity argument 'stringArg' was not supplied.
'WriteSomeText': Value for a required activity argument 'stringArg' was not supplied.
   at System.Activities.Validation.ActivityValidationServices.ThrowIfViolationsExist(IList`1 validationErrors)
   at System.Activities.Hosting.WorkflowInstance.ValidateWorkflow(WorkflowInstanceExtensionManager extensionManager)
   at System.Activities.Hosting.WorkflowInstance.RegisterExtensionManager(WorkflowInstanceExtensionManager extensionManager)
   at System.Activities.WorkflowApplication.EnsureInitialized()
   at System.Activities.WorkflowApplication.RunInstance(WorkflowApplication instance)
   at System.Activities.WorkflowApplication.Invoke(Activity activity, IDictionary`2 inputs, WorkflowInstanceExtensionManager extensions, TimeSpan timeout)
   at System.Activities.WorkflowInvoker.Invoke(Activity workflow, TimeSpan timeout, WorkflowInstanceExtensionManager extensions)
   at System.Activities.WorkflowInvoker.Invoke(Activity workflow)
   at Project1.MainProgram.Main(String[] args) in c:\users\user\documents\visual studio 2010\Projects\ModelingProject1\Project1\MainProgram.cs:line 25

Знам, че предавам само 1 параметър, но изключението все още казва, че ми липсват 3 параметъра. Липсва ми нещо как да направя това правилно.


person Curtor    schedule 06.09.2011    source източник


Отговори (1)


Правилно декларирате stringArg като InArgument, но не му предавате никаква стойност, когато го извиквате вътре в SimpleSequence.

Можете да подадете нещо с помощта на конструктора, докато конструирате самата дейност all, като това:

public class WriteSomeText : CodeActivity
{
    [RequiredArgument]
    public InArgument<string> stringArg { get; set; }

    public WriteSomeText(string stringArg)
    {
        this.stringArg = stringArg;
    }

    protected override void Execute(CodeActivityContext context
    {
        string output = context.GetValue(stringArg);
        System.Console.WriteLine(output);
    }
}

// Calling the activity like this:

internal static void Main(string[] args)
{
    var act = new SimpleSequence()
    {
        Activities =
        {
            new WriteSomeText("hello"),
            new WriteSomeText("world"),
            new WriteSomeText("!")
        }
    };

    WorkflowInvoker.Invoke(act);

    Console.WriteLine("Press any key to exit");
    Console.ReadKey();
}

Също така забележете, че е най-добра практика да използвате конструктора за инициализиране на колекции:

public SimpleSequence()
{
    activities = new Collection<Activity>();
    variables = new Collection<Variable>();
}

Този начин е още по-интуитивен за инициализиране на дейността:

var act = new SimpleSequence()
{
    Activities =
    {
        new WriteSomeText("hello"),
        new WriteSomeText("world"),
        new WriteSomeText("!")
    },
    Variables =
    {
        new Variable<int>("myNewIntVar", 10),
        // ....
    }
};

РЕДАКТИРАНЕ:

Има няколко други начина за подход към проблема. Това е най-добрият ви приятел, докато започвате в света на WF4.

Проверете WF\Basic\CustomActivities\Code-Bodied за малко натискане с този конкретен случай.

person Joao    schedule 06.09.2011
comment
Можете също така да кодирате твърдо stringArg, когато следващата дейност във вашата SimpleSequence е WriteSomeText, но това далеч не е най-добрата практика. Твърдо кодираният е сигнал за това. - person Joao; 06.09.2011
comment
Благодаря за това, но въпросът ми тогава става какъв е смисълът на променливата Variables в SimpleSequence? Каква е предвидената употреба на това, ако всички дейности по кода получат своите параметри по време на изграждане? - person Curtor; 06.09.2011
comment
Трябва да разглеждате Variable‹T› като локална променлива в обикновен метод, използвана за манипулиране и задържане на данни временно. Когато създавате персонализирана дейност, това е точно като предоставяне на метод, който да се използва. Не искате потребителят да докосва локални променливи във вашия метод (или използвате обикновен език за програмиране, или самия WF4). Всеки вход към същия този метод се дава чрез InArgument, който съответства на декларация на аргумент в метод. - person Joao; 06.09.2011
comment
Вашата SimpleSequence или собствена Sequence по този въпрос съдържа Collection‹Variable›, която потребителят да използва докато проектира своя собствена дейност с помощта на дизайнера или чрез код, но отново, за съхраняват и манипулират данни за тяхната конкретна дейност, а не за вашата персонализирана. Ако искате вашата персонализирана дейност да бъде динамична в съответствие с външни променливи, използвайте InArguments. Надявам се, че се изясних. - person Joao; 06.09.2011
comment
В крайна сметка трябва да гледате на WF4 като начин за писане на код чрез код. Това е прост начин да го кажем, но донякъде е вярно. Вие давате персонализирани дейности (методи), които потребителят да извика. Някои NativeActivities са притежатели (като Sequence и няколко други), за да може потребителят да прави каквото иска вътре в него. - person Joao; 06.09.2011
comment
Благодаря много за приноса. В процес съм на анализиране и изпробване на някои от нещата, които сте предложили, но въпреки това обратната връзка е високо ценена. Имах проблеми с намирането на наистина добра документация или примери за подобни неща. - person Curtor; 06.09.2011
comment
Още неща, на които се натъкнах, докато опитвах това: Как бихте присвоили Out или InOutArgument? - person Curtor; 06.09.2011
comment
Давам ви приноса, който исках да имам, докато започвах. Проверете връзката, която публикувах по-горе. Беше най-добрият ми приятел, докато започвах и все още е днес. Късмет. - person Joao; 06.09.2011
comment
OutArguments са свързани със свойството Резултат, ако активност с резултат. Можете да context.SetValue(base.Result, anyValuehere); ако сте в персонализирана дейност или Присвояване активност, ако присвоявате отвън. Отново вижте пробите. Всеки нов въпрос, моля, отворете нов въпрос. наздраве - person Joao; 06.09.2011