1

Ello,我遇到了一个自定义活动的问题,该活动执行对 `ActivityFunc` 的评估并返回 false,即使它在 Execute 中被评估为 true。这是我的活动


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,

            };
        }
    }
}

因此,当我在 Execute 方法中评估我的条件时,即使我将条件的结果打印为真,它也会调用 OnConditionComplete 并返回结果(这总是错误的)。那么这里有什么我看不到的明显错误吗?

更新

好的,我认为 Marice 谈论的是在类中有回调,只是让 OnConditionComplete 方法指向回调。我确实改变了,但没有看到改变。如果我能ActivityFunc<bool> child 在实际执行时以某种方式从条件中检索值或在之后保存它的值,那会很好用。我已经玩过 CacheMetadata 的元数据,看看是否有任何我能找到的东西可以让我这样做,但到目前为止还没有找到任何东西。

更新 2

问题显然来自 ActivityFunc <bool> Condition. 我将不得不通过并检查 Condition 可能存在的问题。不确定这是否应该提出一个新问题,因为它在技术上尚未解决,但我会看到有关组合一个测试条件以退出,如果没有其他任何东西显示我在哪里。

更新 3

好的,这是我用作子活动的一个简单示例,即使它在执行中评估为 true,它也总是返回 false


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
    }
}


4

2 回答 2

1

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"
    };
}
于 2010-10-20T11:48:00.810 回答
1

你好一个我以前从未见过的人,只是碰巧分享了我的 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在 IActivityTemplateFactory 的 Create 方法中设置

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>
于 2010-10-21T18:20:18.317 回答