LoginSignup
1
2

More than 1 year has passed since last update.

UiPath Activity Creatorを使ってみる。(その5:スコープを持ったアクティビティの作成)

Last updated at Posted at 2020-03-22

このドキュメントの概要

 前回 はActivity Creatorでのアクティビティの外観の設定方法について見ていきました。
 今回はスコープをもったアクティビティの作成方法について見ていきます。

WizardでのScope指定

 ActivityCreatorのWizardでACtivityの定義画面でType項目をScopeに設定するとScopeをもったアクティビティになります。また同一のWizard画面内でScopeを持ったアクティビティとSimple設定のアクティビティを作成すると、そのSimpleアクティビティはScopeアクティビティのChildアクティビティとして設定されます。
uac5-1.png
TestScopeアクティビティのプロパティを以下のように設定しました。
uac5-2.png

またTestChildアクティビティのプロパティを以下のように設定しました。
uac5-3.png

TestScopeアクティビティとして以下のコードが自動生成されます。

TestScope.cs
using System;
using System.Activities;
using System.Threading;
using System.Threading.Tasks;
using System.Activities.Statements;
using System.ComponentModel;
using Company.Product3.Activities.Properties;
using UiPath.Shared.Activities;
using UiPath.Shared.Activities.Localization;

namespace Company.Product3.Activities
{
    [LocalizedDisplayName(nameof(Resources.TestScope_DisplayName))]
    [LocalizedDescription(nameof(Resources.TestScope_Description))]
    public class TestScope : ContinuableAsyncNativeActivity
    {
        #region Properties

        [Browsable(false)]
        public ActivityAction<IObjectContainer> Body { get; set; }

        /// <summary>
        /// If set, continue executing the remaining activities even if the current activity has failed.
        /// </summary>
        [LocalizedCategory(nameof(Resources.Common_Category))]
        [LocalizedDisplayName(nameof(Resources.ContinueOnError_DisplayName))]
        [LocalizedDescription(nameof(Resources.ContinueOnError_Description))]
        public override InArgument<bool> ContinueOnError { get; set; }

        [LocalizedDisplayName(nameof(Resources.TestScope_Str_DisplayName))]
        [LocalizedDescription(nameof(Resources.TestScope_Str_Description))]
        [LocalizedCategory(nameof(Resources.Input_Category))]
        public InArgument<string> Str { get; set; }

        // A tag used to identify the scope in the activity context
        internal static string ParentContainerPropertyTag => "ScopeActivity";

        // Object Container: Add strongly-typed objects here and they will be available in the scope's child activities.
        private readonly IObjectContainer _objectContainer;

        #endregion


        #region Constructors

        public TestScope(IObjectContainer objectContainer)
        {
            _objectContainer = objectContainer;

            Body = new ActivityAction<IObjectContainer>
            {
                Argument = new DelegateInArgument<IObjectContainer> (ParentContainerPropertyTag),
                Handler = new Sequence { DisplayName = Resources.Do }
            };
        }

        public TestScope() : this(new ObjectContainer())
        {

        }

        #endregion


        #region Protected Methods

        protected override void CacheMetadata(NativeActivityMetadata metadata)
        {
            if (Str == null) metadata.AddValidationError(string.Format(Resources.ValidationValue_Error, nameof(Str)));

            base.CacheMetadata(metadata);
        }

        protected override async Task<Action<NativeActivityContext>> ExecuteAsync(NativeActivityContext  context, CancellationToken cancellationToken)
        {
            // Inputs
            var str = Str.Get(context);

            return (ctx) => {
                // Schedule child activities
                if (Body != null)
                    ctx.ScheduleAction<IObjectContainer>(Body, _objectContainer, OnCompleted, OnFaulted);

                // Outputs
            };
        }

        #endregion


        #region Events

        private void OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)
        {
            faultContext.CancelChildren();
            Cleanup();
        }

        private void OnCompleted(NativeActivityContext context, ActivityInstance completedInstance)
        {
            Cleanup();
        }

        #endregion


        #region Helpers

        private void Cleanup()
        {
            var disposableObjects = _objectContainer.Where(o => o is IDisposable);
            foreach (var obj in disposableObjects)
            {
                if (obj is IDisposable dispObject)
                    dispObject.Dispose();
            }
            _objectContainer.Clear();
        }

        #endregion
    }
}

Childアクティビティへのデータの受け渡し

 ScopeアクティビティからChildアクティビティへのデータの受け渡しは、ActivityCreatorで用意しているobjectContainerを利用します。
 今回はScopeアクティビティにInArgument<string>型のプロパティStrがありますので、これをChildアクティビティでも使えるようにします。具体的には以下のように _objectContainerにAddメソッドでデータを追加します。

TestScope.cs
()
            // Inputs
            var str = Str.Get(context);
            _objectContainer.Add(str);
            return (ctx) => {
                // Schedule child activities
                if (Body != null)
                    ctx.ScheduleAction<IObjectContainer>(Body, _objectContainer, OnCompleted, OnFaulted);

                // Outputs
            };
()

TestChild側ではobjectContainerインスタンスに対してGet<T>で値を取得します。
以下の例ではTestScopeアクティビティのプロパティとして取得した値の前に"000"を付加してOutStringプロパティとして返しています。

TestChild.cs
()
       protected override async Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken)
        {
            // Object Container: Use objectContainer.Get<T>() to retrieve objects from the scope
            var objectContainer = context.GetFromContext<IObjectContainer>(TestScope.ParentContainerPropertyTag);

            // Inputs
            var str = objectContainer.Get<string>();

            ///////////////////////////
            // Add execution logic HERE
            ///////////////////////////
            str = "000" + str;

            // Outputs
            return (ctx) => {
                OutString.Set(ctx, str);
            };
        }
()

 動作確認のためUiPath Studioで以下のようなワークフローを作成してみます。
uac5-4.png

 TestChildには入力プロパティがありませんが、TestScopeで入力した値を内部で参照しています。そのためTestScopeの入力で仮に"123"とした場合、strOutputには"000123"が返ってきます。

Wizard作成後に別のアクティビティをChildアクティビティにする方法

 Scopeアクティビティを作成した後にChildアクティビティを追加したい場合があると思います。
 この場合はWizardでTypeをSimpleにしたアクティビティを作成した後、以下の設定を加えることによりChildアクティビティにすることができます。
1. using UiPath.Shared.Activities.Utilities; の追加
2. コンストラクタにScope内でのみの利用制限の追加
3. 実行部分にobjectContainerの定義の追加

後で追加したTestChild2アクティビティに対する具体的な変更個所は以下になります。

TestChild2.cs
()

using UiPath.Shared.Activities.Utilities;

(略)
        #region Constructors

        public TestChild2()
        {
            Constraints.Add(ActivityConstraints.HasParentType<TestChild2, TestScope>(string.Format(Resources.ValidationScope_Error, Resources.TestScope_DisplayName)));
        }

        #endregion

(略)
            // Inputs
            var objectContainer = context.GetFromContext<IObjectContainer>(TestScope.ParentContainerPropertyTag);

(略)

次回はnupkg周りの設定について説明します。

(その5 おわり)

その1 その2 その3 その4 その5 その6

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2