LoginSignup
4
1

More than 1 year has passed since last update.

UiPathのデモがしやすくなるカスタムアクティビティをVisual Studioで作ろう

Last updated at Posted at 2022-04-01

UiPathのデモをおこなうことって、よくありますよね。
デモをしている時、今手動なのかロボットが実行しているか分からない。もっとロボットが実行していることをアピールしたいことってありませんか?

今回は、ロボット実行中であることを分かりやすくするカスタムアクティビティを作りました。

Snapshot_20.png

今回は、カスタムアクティビティ作成を時短できるActivity Createrを使用してカスタムアクティビティを作成しています。

Visual Studioでカスタムアクティビティを作りたいと考えている方にも参考になるかと思います。
オリジナルの画像に差し替えたり、機能を追加したりチャレンジしてみてください。

公式ドキュメントはこちらをご覧ください

実際に作ったもの(PresentationRobot)

Youtubeデモはこちら

ソースコードはGithubにアップしています。
Marketplaceには申請中ですので、すぐに使いたい人はGithubからダウンロードしてください。

機能

指定したメッセージをロボット実行中に表示し続けます

効果

  • ロボットが実行中であることが分かります
  • 表示を更新させることで、ロボットが何の操作を行っているか分かります

注意

UiPath Marketplaceで提供されている字幕アクティビティを参考にしています。

字幕アクティビティは、字幕表示中は処理を止めていますが、今回のアクティビティは止めていません。
よって、UiPathのGUI処理が今回作成するアクティビティの表示と重なってしまうとクリックや文字入力ができない可能性がありますのでご注意ください。シミュレートやウィンドウメッセージ送信等のバックグラウンドで動作するオプションを活用いただくか、表示位置を調整してください。

表示メッセージはプロセス終了まで消えずに残り続けますので、メッセージを更新する際はIsFullWidthをTrueにして使用することを推奨します。

作り方

それでは実際にVisual Studioでカスタムアクティビティを作っていきましょう。
当たり前ですが、UiPath Studioは必要ですのでインストールしておいてください。
カスタムアクティビティを作成するには以下のXステップ必要です

  • Visual Studio2019のインストール
  • UiPath Activity Creator 拡張機能の追加
  • UiPathプロジェクトの作成
  • アクティビティの追加
  • 機能の実装
  • パッケージのビルド
  • UiPath Studioで使用

Visual Studio2019のインストール

Visual Studio 2019をインストールします。
.NETデスクトップ開発にチェックを入れておきます。

image.png

UiPath Activity Creator 拡張機能の追加

拡張機能の管理よりUiPathと検索して、UiPath Activity Createrをダウンロードしましょう。1回閉じるとインストールが開始されます。
image.png

プロジェクトの作成と準備

Visual Studioのインストールが終わりましたので、実際にプロジェクトを作成しましょう。
UiPath Standard Activity Projectを選択します。
image.png

プロジェクトの名前を付けます。
ここでは、PresentationRobotとします。
ManabuTech.PresentationRobotとすると、アクティビティパネルではフォルダで構造化されます。
image.png

アクティビティの追加

拡張機能からUiPathの下にある「Add Activities」を選択します。

image.png

Createを選択
image.png

+ボタンからアクティビティを追加します
Name、Descriptionを設定します。
TypeはSimpleにしています。必須項目がGUI上で設定できます。
image.png

Define Activities上にあるPropertiesのEditをクリックして引数を追加します。
ImageとPositionは後ほどコード上で独自のEnum型を指定するためString型のままにしています。

image.png

機能の実装

アセンブリ参照の追加

アセンブリ参照より、System.Windows.Formsを追加します
image.png

リソースの追加

使用する画像をリソースに追加します
image.png

コンボボックスに表示するパラメータの追加

コンボボックスで使用するパラメータを定義します
PresentationRobot\Enumsの下にPositionType.csとImageType.csを追加して次のように定義します

PositionType.cs

using System.ComponentModel;
namespace PresentationRobot.Enums
{
    public enum PositionType
    {
        [Description("Top Left")]
        TopLeft,
        [Description("Top Right")]
        TopRight,
        [Description("Down Left")]
        DownLeft,
        [Description("Down Right")]
        DownRight
    }
}

ImageType.cs

using System.ComponentModel;
namespace PresentationRobot.Enums
{
    public enum ImageType
    {
        [Description("Flying Robo")]
        Flying Robot,
        [Description("Processing Robot")]
        Processing Robot,
        [Description("Listening Robot")]
        Listening Robot,
        [Description("Recorder Robot")]
        Recorder Robot,
        [Description("Searching Robot")]
        Searching Robot,
        [Description("Receiving Robot")]
        Receiving Robot
    }
}

参照とプロパティの修正

定義したEnumとFormを使用するため追加しています
EnumやBooleanで定義するとプロパティ上でチェックボックスやコンボボックスとして表示されます。

Presentation.cs

using System;
using System.Activities;
using System.Threading;
using System.Threading.Tasks;
using System.Drawing;
using ManabuTech.Activities.Properties;
using UiPath.Shared.Activities;
using UiPath.Shared.Activities.Localization;

// Add
using PresentationRobot.Enums;
using System.ComponentModel;
using System.Windows.Forms; // Form アセンブリ参照の追加が必要

~~~
        #region Properties

        /// <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.DisplayMessage_Message_DisplayName))]
        [LocalizedDescription(nameof(Resources.DisplayMessage_Message_Description))]
        [LocalizedCategory(nameof(Resources.Input_Category))]
        [DefaultValue("ロボット実行中")]
        public InArgument<string> Message { get; set; } = "ロボット実行中";

        [LocalizedDisplayName(nameof(Resources.DisplayMessage_FontSize_DisplayName))]
        [LocalizedDescription(nameof(Resources.DisplayMessage_FontSize_Description))]
        [LocalizedCategory(nameof(Resources.Input_Category))]
        [DefaultValue(50)]
        public InArgument<int> FontSize { get; set; } = 50;

        [LocalizedDisplayName(nameof(Resources.DisplayMessage_TextColor_DisplayName))]
        [LocalizedDescription(nameof(Resources.DisplayMessage_TextColor_Description))]
        [LocalizedCategory(nameof(Resources.Input_Category))]
        [DefaultValue(typeof(Color), "White")]
        public InArgument<Color> TextColor { get; set; } = Color.White;

        [LocalizedDisplayName(nameof(Resources.DisplayMessage_BackgroundColor_DisplayName))]
        [LocalizedDescription(nameof(Resources.DisplayMessage_BackgroundColor_Description))]
        [LocalizedCategory(nameof(Resources.Input_Category))]
        [DefaultValue(typeof(Color), "Black")]
        public InArgument<Color> BackgroundColor { get; set; } = Color.Black;

        [LocalizedDisplayName(nameof(Resources.DisplayMessage_BackgroundOpacity_DisplayName))]
        [LocalizedDescription(nameof(Resources.DisplayMessage_BackgroundOpacity_Description))]
        [LocalizedCategory(nameof(Resources.Input_Category))]
        [DefaultValue(0.9)]
        public InArgument<Double> BackgroundOpacity { get; set; } = 0.9;

        [LocalizedDisplayName(nameof(Resources.DisplayMessage_Image_DisplayName))]
        [LocalizedDescription(nameof(Resources.DisplayMessage_Image_Description))]
        [LocalizedCategory(nameof(Resources.Input_Category))]
        public ImageType Image { get; set; }

        [LocalizedDisplayName(nameof(Resources.DisplayMessage_Position_DisplayName))]
        [LocalizedDescription(nameof(Resources.DisplayMessage_Position_Description))]
        [LocalizedCategory(nameof(Resources.Input_Category))]
        public PositionType Position { get; set; }

        [LocalizedDisplayName(nameof(Resources.DisplayMessage_IsFullWidth_DisplayName))]
        [LocalizedDescription(nameof(Resources.DisplayMessage_IsFullWidth_Description))]
        [LocalizedCategory(nameof(Resources.Input_Category))]
        public Boolean IsFullWidth { get; set; }

        #endregion

機能の実装

フォントサイズからフォームのサイズを指定しています。

        protected override async Task<Action<AsyncCodeActivityContext>> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken)
        {
            // Inputs
            var message = Message.Get(context);
            var fontsize = FontSize.Get(context);
            var textcolor = TextColor.Get(context);
            var backgroundcolor = BackgroundColor.Get(context);
            var backgroundopacity = BackgroundOpacity.Get(context);
            //var image = Image.Get(context);
            //var position = Position.Get(context);
            //var isfullwidth = IsFullWidth.Get(context);
            var position = Position;
            var image = Image;
            var isfullwidth = IsFullWidth;

            ///////////////////////////
            // Add execution logic HERE
            ///////////////////////////

            // Add From --->

            var label = new Label
            {
                Font = new Font("Arial", fontsize, FontStyle.Bold),
                TextAlign = ContentAlignment.MiddleLeft,
                Text = message,
                AutoSize = true,
                ForeColor = textcolor
            };

            var pictureBox = new PictureBox
            {
                Width = label.PreferredHeight,
                Height = label.PreferredHeight
            };

            label.Left = pictureBox.Width + 10;
            label.Top = 10;
            pictureBox.Left = 10;

            //画像を表示する
            switch (image)
            {
                default:
                case ImageType.FlyingRobot:
                    pictureBox.Image = Properties.Resources.Flying_Robot;
                    break;
                case ImageType.ListeningRobot:
                    pictureBox.Image = Properties.Resources.Listening_Robot;
                    break;
                case ImageType.ProcessingRobot:
                    pictureBox.Image = Properties.Resources.Processing_Robot;
                    break;
                case ImageType.RecorderRobot:
                    pictureBox.Image = Properties.Resources.Recorder_Robot;
                    break;
                case ImageType.SearchingRobot:
                    pictureBox.Image = Properties.Resources.Searching_Robot;
                    break;
                case ImageType.ReceivingRobot:
                    pictureBox.Image = Properties.Resources.Receiving_Robot;
                    break;
            }

            //画像の大きさをPictureBoxに合わせる
            pictureBox.SizeMode = PictureBoxSizeMode.StretchImage;

            var form = new Form
            {
                Width = pictureBox.Left + pictureBox.Width + label.PreferredWidth + 20,
                Height = label.PreferredHeight + 10,
                BackColor = backgroundcolor,
                Opacity = backgroundopacity,
                FormBorderStyle = FormBorderStyle.None,
                TopMost = true
            };

            form.Show();

            switch (position)
            {
                case PositionType.DownLeft:
                    form.Left = 0;
                    form.Top = Screen.PrimaryScreen.WorkingArea.Height - form.Height;
                    break;
                case PositionType.DownRight:
                    form.Left = Screen.PrimaryScreen.WorkingArea.Width - form.Width;
                    form.Top = Screen.PrimaryScreen.WorkingArea.Height - form.Height;
                    break;
                case PositionType.TopLeft:
                    form.Left = 0;
                    form.Top = 0;
                    break;
                case PositionType.TopRight:
                    form.Left = Screen.PrimaryScreen.WorkingArea.Width - form.Width;
                    form.Top = 0;
                    break;
            }
            
            if (isfullwidth)
            {
                form.Left = 0;
                form.Width = Screen.PrimaryScreen.WorkingArea.Width;
            }

            form.Controls.Add(pictureBox);
            form.Controls.Add(label);
            form.Update();

            // デバッグ時、有効にする
            //System.Threading.Thread.Sleep(3000);
            //form.Close();

            // Add To <---

            // Outputs
            return (ctx) => {
            };
        }

Designerの修正

PresentationDesigner.xamlから不要な部分を削除します
今回はMessageのみをGUIに表示するようにしますので、Message以外を削除します。

            <Label Content="{x:Static activity:Resources.DisplayMessage_Message_DisplayName}" Grid.Row="0"
                   ToolTip="{x:Static activity:Resources.DisplayMessage_Message_Description}"/>
            <sapv:ExpressionTextBox Grid.Row="1" ExpressionType="{Binding ModelItem.Properties[Message].PropertyType.GenericTypeArguments[0]}" OwnerActivity="{Binding Path=ModelItem}" HintText="{x:Static activity:Resources.DisplayMessage_Message_Description}" UseLocationExpression="False">
                <sapv:ExpressionTextBox.Expression>
                    <Binding Path="ModelItem.Message" Converter="{StaticResource ArgumentToExpressionConverter}" Mode="TwoWay" ConverterParameter="In" UpdateSourceTrigger="PropertyChanged" />
                </sapv:ExpressionTextBox.Expression>
            </sapv:ExpressionTextBox>

        </Grid>

パッケージのビルド

Activities.Designプロジェクトを選択してビルドから発行をクリック
image.png

発行プロファイルの追加から、フォルダを選択して次へを選択
image.png

必須コンポーネントが必要な場合はインストールしてください。
image.png

フォルダーの場所を指定して完了をクリック
image.png

Debugを選択して発行で指定フォルダにnupkgが作成されます
image.png

UiPath Studioで使用

パッケージ管理フォルダを指定
image.png

作成したパッケージをインストールして保存
image.png

同意するを選択
image.png

最後に

いかがでしたでしょうか?
UiPath Studioで作成したワークフローをデモする際には、ぜひこのアクティビティを使用してみてください。
余力があれば、画像を差し替えてカスタマイズしてみてはいかがでしょうか?

4
1
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
4
1