1

こんにちは、'ActivityFunc' の評価を実行し、Execute で true と評価されても false を返すカスタム アクティビティに問題があります。ここに私の活動があります


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 メソッドで評価されると、条件の結果を true に出力しても、OnConditionComplete が結果 (常に false) で呼び出されます。それで、私が見ていない明らかに間違っていることがありますか?

アップデート

Marice は、クラス内にコールバックを持ち、OnConditionComplete メソッドがコールバックを指すようにすることについて話していると思います。私はそれを変更しましたが、変更は見られませんでした。実際に実行したときに条件から値を取得しActivityFunc<bool> child たり、後でその値を保存したりできれば、それはうまくいくでしょう。私は CacheMetadata のメタデータをいじって、それを可能にするものがあるかどうかを確認しましたが、まだ何も見つかりませんでした。

更新 2

問題は明らかに ActivityFunc <bool> 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
            }
        };
    }
}

この 2 つをワークフロー コンソール アプリにドロップし、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>

問題はアクティビティにあるのではなく、アクティビティの使い方にあります。テスト装置が正しくない場合でも、それが正しいと想定しています。


今後の参考のために...私にこれが起こった場合、原因はResultIActivityTemplateFactoryの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 に答える