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

Я пытаюсь создать пользовательское действие для WF4, в котором размещается дочернее действие и передаю некоторые аргументы его дочернему действию. Ниже я прикрепляю упрощенную версию моей деятельности (Родитель и Ребенок)

public class Child : CodeActivity
{
    public InArgument<Dictionary<string, object>> Data;

    protected override void Execute(CodeActivityContext context)
    {
        Dictionary<string, object> data = Data.Get(context);

        //Some operations on the input data
    }
}


 public class Parent : NativeActivity
{
    public InArgument<int> Value1 { get; set; }

    public InArgument<string> Value2 { get; set; }

    public Child Body { get; set; }


    protected override void Execute(NativeActivityContext context)
    {
        int value1 = Value1.Get(context);
        string value2 = Value2.Get(context);

        Dictionary<string, object> data = new Dictionary<string, object>();
        data.Add("value1", value1);
        data.Add("value2", value2);

        context.SetValue(Body.Data, data);

        context.ScheduleActivity(this.Body);
    }


    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        Body = new Child();

        base.CacheMetadata(metadata);
    }
}

Аргумент Data из действия Child имеет значение null, когда выполнение рабочего процесса достигает метода Execute для действия.

Может кто-нибудь, пожалуйста, дайте мне какое-то направление, как можно передать аргументы между этими двумя действиями?


person axl g    schedule 04.04.2011    source источник


Ответы (3)


В то время как подход с дополнительной переменной работает, «официальный» способ планирования дочернего элемента с некоторыми входными данными используется в ActivityAcytion или, если вы также хотите получить результат с помощью ActivityFunc.

Я боюсь, что код на самом деле не станет проще или понятнее, но для полноты картины я просто решил добавить это.

public class Child : CodeActivity<object>
{
    public InArgument<Dictionary<string, object>> Data { get; set; }

    protected override object Execute(CodeActivityContext context)
    {
        Dictionary<string, object> data = Data.Get(context);

        foreach (var item in data)
        {
            Console.WriteLine(item);
        }

        return "Some result";
    }
}



public class Parent : NativeActivity<object>
{
    public InArgument<int> Value1 { get; set; }
    public InArgument<string> Value2 { get; set; }

    public ActivityFunc<Dictionary<string, object>, object> Body { get; set; }

    protected override void Execute(NativeActivityContext context)
    {
        int value1 = Value1.Get(context);
        string value2 = Value2.Get(context);

        Dictionary<string, object> data = new Dictionary<string, object>();
        data.Add("value1", value1);
        data.Add("value2", value2);

        context.ScheduleFunc<Dictionary<string, object>, object>(Body, data, ChildCompletionCallback);
    }


    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        var arg = new DelegateInArgument<Dictionary<string, object>>();

        Body = new ActivityFunc<Dictionary<string, object>, object>
        {
            Argument = arg,
            Handler = new Child() { Data = arg }
        };

        base.CacheMetadata(metadata);
    }

    private void ChildCompletionCallback(NativeActivityContext context, ActivityInstance completedInstance, object result)
    {
        //Set the output for the parent activity at the completion of the child activity
        this.Result.Set(context, result);
    }
}
person Maurice    schedule 05.04.2011
comment
Спасибо за ответ Морис! Есть ли у вас какие-либо идеи, повлияет ли использование подхода ActivityAction\ActivityFunc или подхода с промежуточной переменной на производительность во время выполнения? - person axl g; 05.04.2011
comment
Я никогда не проводил здесь никаких измерений производительности, но сомневаюсь, что будет заметная разница в производительности. Довольно редко мне нужны ActivityAction или ActivityFunc, и в этих случаях я просто запускаю их. Кстати, я добавил это в свой блог с небольшим объяснением: msmvps.com/blogs/theproblemsolver/archive/2011/04/05/ - person Maurice; 05.04.2011
comment
Есть ли способ сделать Body ActivityFunc невидимым для потребителей? Если я установлю его как частный или защищенный, выполнение прервется при планировании дочерней активности. В противном случае, будучи общедоступным, он виден дизайнеру, и теоретически он может быть изменен потребителем на что-то другое, а я бы не хотел, чтобы это произошло. - person axl g; 08.04.2011
comment
Да, посмотрите пример в моем блоге. В основном вам нужно зарегистрировать ActivityFunc с помощью AddImplementationDelegate(), и он может быть закрытым и не отображаться в XAML. - person Maurice; 08.04.2011

Мне также нужно было вернуть результат дочерней активности через родительскую активность. Для этого я использовал метод ScheduleActivity с CompletionCallback. Я прикрепил ниже примеры действий Parent/Child, содержащие также набор аргументов out, возможно, это кому-то когда-нибудь понадобится :)

Родитель:

public class Parent : NativeActivity<object>
{
    public InArgument<int> Value1 { get; set; }
    public InArgument<string> Value2 { get; set; }
    private Variable<Dictionary<string, object>> SomeVariable { get; set; } // intermediate variable

    private Child Body { get; set; }

    public Parent()
    {
        this.SomeVariable = new Variable<Dictionary<string, object>>("SomeVariable");

        this.Body = new Child();
        this.Body.Data = new InArgument<Dictionary<string, object>>(SomeVariable);
    }

    protected override void Execute(NativeActivityContext context)
    {
        int value1 = Value1.Get(context);
        string value2 = Value2.Get(context);

        Dictionary<string, object> data = new Dictionary<string, object>();
        data.Add("value1", value1);
        data.Add("value2", value2);

        this.SomeVariable.Set(context, data);

        context.ScheduleActivity(this.Body, ChildCompletionCallback);
    }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        base.CacheMetadata(metadata);

        // needs to be cached as implementation child and variable (Body and SomeVariable must be declared as private then)
        metadata.AddImplementationChild(this.Body);
        metadata.AddImplementationVariable(SomeVariable);
    }

    private void ChildCompletionCallback<TResult>(NativeActivityContext context, ActivityInstance completedInstance, TResult result)
    {
        //Set the output for the parent activity at the completion of the child activity
        this.Result.Set(context, result);
    }
}

Ребенок:

public class Child : CodeActivity<object>
{
    public InArgument<Dictionary<string, object>> Data { get; set; }

    protected override object Execute(CodeActivityContext context)
    {
        Dictionary<string, object> data = Data.Get(context);

        return "Some result";
    }
}
person axl g    schedule 05.04.2011

вероятно, невозможно установить значение входного аргумента непосредственно в методе Execute. Необходимо ввести промежуточную переменную. Аргумент Child.Data связан с этой переменной и в методе Parent.Execute.

Родитель:

public class Parent : NativeActivity
{
    public InArgument<int> Value1 { get; set; }
    public InArgument<string> Value2 { get; set; }
    private Variable<Dictionary<string, object>> SomeVariable { get; set; } // intermediate variable

    private Child Body { get; set; }

    public Parent()
    {
        this.SomeVariable = new Variable<Dictionary<string, object>>("SomeVariable");

        this.Body = new Child();
        this.Body.Data = new InArgument<Dictionary<string, object>>(SomeVariable);
    }

    protected override void Execute(NativeActivityContext context)
    {
        int value1 = Value1.Get(context);
        string value2 = Value2.Get(context);

        Dictionary<string, object> data = new Dictionary<string, object>();
        data.Add("value1", value1);
        data.Add("value2", value2);

        this.SomeVariable.Set(context, data);

        context.ScheduleActivity(this.Body);
    }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        base.CacheMetadata(metadata);

        // needs to be cached as implementation child and variable (Body and SomeVariable must be declared as private then)
        metadata.AddImplementationChild(this.Body);
        metadata.AddImplementationVariable(SomeVariable);
    }
}

Ребенок:

public class Child : CodeActivity
{
    // Must be declared as property.
    public InArgument<Dictionary<string, object>> Data
    {
        get;
        set;
    }

    protected override void Execute(CodeActivityContext context)
    {
        var data = this.Data.Get(context);
    }
}

Это нехорошее решение, но я почти не вижу ничего хорошего в WF4 :).

person Jakub Linhart    schedule 04.04.2011
comment
Для меня это хорошее решение, потому что оно работает, и мне действительно нужно было, чтобы это работало. :) Большое спасибо за помощь, Якуб! - person axl g; 04.04.2011