Workflow Foundation 4 — результаты ActivityFunc‹bool› всегда ложны, даже если Execute Method показывает true

Здравствуйте, у меня возникла проблема с настраиваемой активностью, которая выполняет предварительную оценку `ActivityFunc` и возвращает false, даже если она оценивается в Execute как истинная. Вот мои действия


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.ComponentModel;
using System.Activities.Presentation;

namespace SomeActivities
{
    /// 
    /// Root of any number of activities used to check for a specific set of conditions to be true (Trigger Conditions) 
    /// 
    public sealed class Trigger : NativeActivity, IActivityTemplateFactory
    {
        /// 
        /// The initial Condition that determines if the trigger should be scheduled
        /// 
        /// The condition.
        [RequiredArgument]
        public ActivityFunc <bool> Condition { get; set; }

        /// 
        /// The resulting action that is scheduled if the Condition is true
        /// 
        /// The child.
        [RequiredArgument]
        public ActivityAction Child { get; set; }

        /// 
        /// Gets or sets the value holding whether or not the trigger matches the condition
        /// 
        /// The type of the match.
        public MatchType MatchType{ get; set; }

        private CompletionCallback<bool> OnExecutionCompleteCallBack;

        protected override void Execute(NativeActivityContext context)
        {
            this.OnExecutionCompleteCallBack = this.OnConditionComplete;
            context.ScheduleFunc<bool>(this.Condition, this.OnExecutionCompleteCallBack);
        }

        public void OnConditionComplete(NativeActivityContext context, ActivityInstance instance, bool result)
        {
            if (instance.State == ActivityInstanceState.Canceled)
            {
                context.Abort();
                return;
            }

            //check if Condition evaluation returns true
            //Always show as false
            if (result)
            {
                //If so then schedule child Activity
                context.ScheduleAction(Child);
            }
        }

        Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
        {
            return new Trigger()
            {
                Child = new ActivityAction()
                {
                    DisplayName = "Trigger Child Action"
                },

                Condition = new ActivityFunc<bool>()
                {
                    DisplayName = "Trigger Conditionals",
                    Result = new DelegateOutArgument<bool>()
                },
                DisplayName = "Trigger",
                MatchType = MatchType.Matches,

            };
        }
    }
}

Поэтому, когда мое условие оценивается в методе выполнения, он вызывает OnConditionComplete с результатом (что всегда ложно), даже если я печатаю результат условия как истинный. Значит, здесь что-то явно не так, чего я не вижу?

Обновить

Хорошо, я думаю, что Марис говорила о том, что обратный вызов в классе и просто метод OnConditionComplete указывает на обратный вызов. Я менял, но изменений не увидел. Если бы я мог каким-то образом получить значение из условия ActivityFunc<bool> child при его фактическом выполнении или сохранить его значение после этого, это сработало бы отлично. Я поигрался с метаданными CacheMetadata, чтобы посмотреть, есть ли что-нибудь, что я мог бы найти, что позволило бы мне это сделать, но пока ничего не нашел.

Обновление 2

Проблема, по-видимому, исходит от ActivityFunc <bool> Condition. Мне нужно пройти и проверить, в чем могут быть проблемы с условием. Не уверен, следует ли это перейти к новому вопросу или нет, поскольку он технически не решен, но я посмотрю, как составить тестовое условие, чтобы выйти из него, и, если ничего другого, показать, где я нахожусь.

Обновление 3

Хорошо, это простой пример того, что я использую в качестве дочерней активности, которая всегда возвращает false, даже если при выполнении она оценивается как true.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.Activities.Presentation;
using System.ComponentModel;
using System.Drawing;

namespace SomeActivities
{
    public sealed class DataHandlerTypeName : NativeActivity,IActivityTemplateFactory
    {
        // Define an activity input argument of type string
        [RequiredArgument]
        public InArgument ImportContext { get; set; }

        /// 
        /// Gets or sets the handler type name to check.
        /// 
        /// The handler type name to check.
        [RequiredArgument]
        public string HandlerTypeNameToCheck { get; set; }


        /// 
        /// Performs the trigger check for the matching Data Type Handler Names
        /// 
        /// The context.
        protected override void Execute(NativeActivityContext context)
        {
            var ic = this.ImportContext.Get(context);

            if (1==1)
            {
                //context.SetValue(base.Result, true);
                Result.Set(context, true);
            }
            else 
            {
                //context.SetValue(base.Result, true);
                Result.Set(context, false);
            }
        }

        #region IActivityTemplateFactory Members


        Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
        {
            return new DataHandlerTypeName()
            {
                ImportContext = this.ImportContext,
                HandlerTypeNameToCheck = "Default"
            };
        }

        #endregion
    }
}



person Terrance    schedule 18.10.2010    source источник


Ответы (2)


Привет, кто-то, кого я никогда раньше не встречал, и просто случайно поделился своим IP-адресом.

Вы делаете что-то не так. В другом месте, то есть.

Либо DLL с действиями, которые вы используете, устарела, либо определение рабочего процесса устарело и не содержит того, что, по вашему мнению, он делает. Или это что-то совсем другое.

Я сократил ваш код и сжал его в образец проекта. Нравится видеть это здесь мы идем:

Это простое условие:

public sealed class AnTrigger : NativeActivity<bool>
{
    public bool ResultToSet { get; set; }

    protected override void Execute(NativeActivityContext context)
    {
        Result.Set(context, ResultToSet);
    }
}

Просто, нет? Вот хост, который оценивает это условие и, если оно возвращает true, запускает одно дочернее действие. Обратите внимание: я создаю действие в методе Create, поэтому мне не нужно создавать редактор.

public sealed class AnTriggerHost : NativeActivity, IActivityTemplateFactory
{
    public ActivityFunc<bool> Condition { get; set; }
    public ActivityAction Child { get; set; }

    protected override void Execute(NativeActivityContext context)
    {
        context.ScheduleFunc(Condition, OnConditionComplete);
    }

    private void OnConditionComplete(
        NativeActivityContext context, 
        ActivityInstance completedInstance, 
        bool result)
    {
        if (result)
            context.ScheduleAction(Child);
    }

    Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
    {
        // so I don't have to create UI for these, here's a couple samples
        // seq is the first child and will run as the first AnTrigger is configured to return true
        // so the first trigger evals to true and the first child runs, which
        var seq = new Sequence
        {
            DisplayName = "Chief Runs After First Trigger Evals True"
        };
        // prints this message to the console and
        seq.Activities.Add(new WriteLine { Text = "See this?  It worked." });
        // runs this second trigger host, which 
        seq.Activities.Add(
            new AnTriggerHost
            {
                DisplayName = "This is the SECOND host",
                Condition = new ActivityFunc<bool>
                {
                    // will NOT be triggered, so you will never see
                    Handler = new AnTrigger
                    {
                        ResultToSet = false,
                        DisplayName = "I return false guize"
                    }
                },
                Child = new ActivityAction
                {
                    // this activity write to the console.
                    Handler = new WriteLine
                    {
                        Text = "you won't see me"
                    }
                }
            });

        return new AnTriggerHost
        {
            DisplayName = "This is the FIRST host",
            Condition = new ActivityFunc<bool>
            {
                Handler = new AnTrigger
                {
                    ResultToSet = true,
                    DisplayName = "I return true!"
                }
            },
            Child = new ActivityAction
            {
                Handler = seq
            }
        };
    }
}

Поместите эти два в приложение Workflow Console и поместите AnTriggerHost в рабочий процесс. Установите пару точек останова и наблюдайте, как он летает. Вот рабочий процесс xaml:

  <local:AnTriggerHost DisplayName="This is the FIRST host" >
    <local:AnTriggerHost.Child>
      <ActivityAction>
        <Sequence DisplayName="Chief Runs After First Trigger Evals True">
          <WriteLine Text="See this?  It worked." />
          <local:AnTriggerHost DisplayName="This is the SECOND host">
            <local:AnTriggerHost.Child>
              <ActivityAction>
                <WriteLine Text="you won't see me" />
              </ActivityAction>
            </local:AnTriggerHost.Child>
            <local:AnTriggerHost.Condition>
              <ActivityFunc x:TypeArguments="x:Boolean">
                <local:AnTrigger DisplayName="I return false guize" ResultToSet="False" />
              </ActivityFunc>
            </local:AnTriggerHost.Condition>
          </local:AnTriggerHost>
        </Sequence>
      </ActivityAction>
    </local:AnTriggerHost.Child>
    <local:AnTriggerHost.Condition>
      <ActivityFunc x:TypeArguments="x:Boolean">
        <local:AnTrigger DisplayName="I return true!" ResultToSet="True" />
      </ActivityFunc>
    </local:AnTriggerHost.Condition>
  </local:AnTriggerHost>

Ваша проблема заключается не в действиях, а в том, как вы их используете. Вы предполагаете, что ваша тестовая установка верна, когда это не так.


Для дальнейшего использования... Когда это происходит со мной, причина в том, что я установил Result в методе Create IActivityTemplateFactory.

Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
    return new Child
    {
        InputText = new InArgument<string>(
            new VisualBasicValue<string>(Parent.InputTextVariable)),
        // the following demonstrates what NOT to do in the Create method. 
        // this BREAKS your ActivityFunc, which will ALWAYS return default(T)
        // DO NOT SET Result AT ANY TIME OR IN ANY PLACE
        // BEGIN ERROR
        Result = new OutArgument<string>()
        // END ERROR
    };
}

Это приводит к набору результатов в определении рабочего процесса, что нарушает шаблон ActivityFunc.

<!--If you see ActivityFunc.Result in your workflow, DELETE IT -->
<ActivityFunc.Result>
  <DelegateOutArgument x:TypeArguments="x:String" />
</ActivityFunc.Result>
person Community    schedule 21.10.2010

ScheduleFunc всегда принимает ActivityFunc, где ваше условие определяется как ActivityFunc. Не уверен, откуда взялся не универсальный ActivityFunc. Также CompletionCallback должен быть CompletionCallback.

Обновление: тестовый код, который я использовал:

IActivityTemplateFactory factory = new Trigger();
var trigger = (Trigger)factory.Create(null);
trigger.Condition.Handler = new AlwaysTrue();
trigger.Child.Handler = new WriteLine()
{
    Text = "Its true."
};
WorkflowInvoker.Invoke(trigger);

class AlwaysTrue : CodeActivity<bool>
{
    protected override bool Execute(CodeActivityContext context)
    {
        return true;
    }
}

И IActivityTemplateFactory.Create:

Activity IActivityTemplateFactory.Create(System.Windows.DependencyObject target)
{
    return new Trigger()
    {
        Child = new ActivityAction()
        {
            DisplayName = "Trigger Child Action"
        },

        Condition = new ActivityFunc<bool>()
        {
            DisplayName = "Trigger Conditionals"
        },
        DisplayName = "Trigger"
    };
}
person Maurice    schedule 20.10.2010
comment
2.CompletionCallback должен быть CompletionCallback. -CompletionCallback — это CompletionCallback, я создаю его экземпляр в методе расписания. Если нет другого способа, которым я должен это делать? - person Terrance; 20.10.2010
comment
1.ScheduleFunc всегда принимает ActivityFunc, где ваше условие определяется как ActivityFunc. Не слишком уверен, что вы имеете в виду. Ссылка находится здесь msdn.microsoft.com/en-us/library/dd486077. aspx, а мое условие определено как ActivityFunc. - person Terrance; 20.10.2010
comment
Хм. Кажется, я терял некоторое форматирование. Он должен был читать ActivityFunc ‹ T › - person Maurice; 20.10.2010
comment
Да, да, я сделал то же самое. Должно быть исправлено сейчас. и код должен иметь гораздо больше смысла. - person Terrance; 20.10.2010
comment
Да, это так :-) Удаление строки с Result = new DelegateOutArgument ‹ bool › () из IActivityTemplateFactory.Create(), кажется, решает проблему для меня. - person Maurice; 20.10.2010
comment
Я попробовал это и до сих пор не получаю ничего, кроме false, переданного методу OnConditionComplete. - person Terrance; 20.10.2010
comment
Это мой тестовый рабочий процесс, и он отлично работает: IActivityTemplateFactory factory = new Trigger(); var trigger = (Триггер) factory.Create (null); trigger.Condition.Handler = новый AlwaysTrue(); trigger.Child.Handler = new WriteLine() { Text = Это правда. }; WorkflowInvoker.Invoke(триггер); - person Maurice; 20.10.2010
comment
Ваш тест работает нормально, но я все еще получаю ложные результаты от моих условий ActivtyFunc‹bool›, которые я пытаюсь использовать в своем производственном коде. Так что, похоже, они могут быть виновниками. - person Terrance; 20.10.2010
comment
Что ж, спасибо, что помогли мне понять одну из вещей, которых нет. - person Terrance; 21.10.2010