【UiPath】カスタムアクティビティのアイコンを変更する

[前回](https://qiita.com/UmegayaRollcake/items/c9ff9a01b101ba9193fc)はUiPathガイドに沿って、カスタムアクティビティを作るために必要な各種インストール作業と
超簡単なカスタムアクティビティを作ってみるところまで実践しました。

せっかくアクティビティが自作できるのなら、**"俺のアクティビティ感"**をぜひ出したい。
そのためにまず見た目（アイコン）を変えてみましょう。

が、これが思った以上に難しい。
NuGet Package Explorerに"Icon URL"というプロパティがあったので、
そこにアイコン画像のパスを書けばいいんでしょ？と思ったら全然そんな事は無くて、
思いっきりWindows Workflow Foundationの世界に入り込む必要がありました。

今の日時を文字列で返す"Get Now"アクティビティを作ってみる想定で、まず見た目から入ります。

# Activity Designer
アクティビティの見た目を定義するActivity Designerという仕組みがあるのでそれを使います。

まず自作アクティビティのVisual Studioプロジェクトに「アクティビティデザイナー」を追加。
　![designer.png](https://qiita-image-store.s3.amazonaws.com/0/255097/4ad65d7c-b3ec-0df1-da93-d75d5674bce6.png)

今回は自作アクティビティ名を"GetNow"としているので、それに合わせて"GetNowDesinger"と名付けます。

こんな画面が出ました。まさにアクティビティのデザイン画面です。
下のペインに正体のXAMLコードが表示されていて、ココを直すと上のデザインに反映されます。
　![default.png](https://qiita-image-store.s3.amazonaws.com/0/255097/e311ed71-2240-fd21-e2a4-07e26eb4b258.png)

# アクティビティとActivity Designerのリンク
作ったActivity Designerをアクティビティのクラスにリンクさせます。
やり方は簡単。クラスのAttributeに"[Designer(typeof(Designerクラス名))]"を追加するだけ。

```
namespace Umemaru.Activities
{
    [DisplayName("Get Now")]
    [Designer(typeof(GetNowDesigner))]
    public class GetNow : CodeActivity
    {
```


# アイコンの絵を用意
アイコンにする絵を用意します。
ただし、絵といっても画像ファイルじゃなくてXAML形式のコードになります。
※画像ファイルはUiPathのアイコンに使えません。そのへんの経緯は最後にまとめました。

このXAMLアイコンのやり方は[GitHub](https://github.com/UiPath/Community.Activities)に公開されているUiPath公式のカスタムアクティビティ
（ScriptActivity）でも採用されているので、UiPath的にはこれが正解なのでしょう。
　![desinger.png](https://qiita-image-store.s3.amazonaws.com/0/255097/8304f1ac-7a5d-b7fc-5e38-20e702415d9b.png)
（このアイコン、XAMLコードで書かれてます）

といってもXAMLコードを手で書く必要は無く、ツールを使います。
つ [[Microsoft Expression Design 4](https://www.microsoft.com/en-us/download/details.aspx?id=36180)]

このサイトには罠があり、English版しかダウンロードできないと思わせといて
(+)Detailのツリーを開くとJapanese版のリンクが出てきます。なんだそれ。

Expression Design自体の使い方は他のサイトにおまかせして、ここではポイントだけ紹介。

まず絵を描く。（時計アイコンは既にDelayで使われているので、腕時計にします。）
　![watch.png](https://qiita-image-store.s3.amazonaws.com/0/255097/72c98e8c-7179-1c97-a8cd-095427fa1496.png)

ポイントは、"不透明度"を0%(=透明)にしたタテヨコ同じ長さのダミー四角形を背景に置く事。
XAMLにした時にアスペクト比が崩れずに済みます。
　![tech.png](https://qiita-image-store.s3.amazonaws.com/0/255097/09c0aedd-4917-86b1-46d3-335d921f1491.png)

ファイル＞エクスポート＞"XAML WPF リソースディクショナリ"形式でXAMLファイルを出力。
　![export.png](https://qiita-image-store.s3.amazonaws.com/0/255097/e082d924-d90c-9152-ea4b-69c862d34822.png)

Expression Designの出番はここまで。Visual Studioに戻ります。

# アイコンをActivity Designerに設定
エクスポートしたXAMLファイルをテキストで開き、
\<DrawingBrush.Drawing>～\</DrawingBrush.Drawing> までをコピーし、
アクティビティデザイナーのコードペインの\<Grid>タグの上に↓のタグを追加します。

```
    <sap:ActivityDesigner.Icon>
        <DrawingBrush>
            <DrawingBrush.Drawing>
                ～中略（コピーしたXAMLを貼り付け）～
            </DrawingBrush.Drawing>
        </DrawingBrush>
    </sap:ActivityDesigner.Icon>
```

描いた絵が反映されます。いいねいいね、テンション上がってきた！
　![desinger.png](https://qiita-image-store.s3.amazonaws.com/0/255097/c7403d9f-2805-c897-501f-13b3507e2b02.png)

この後は前回の手順に沿ってビルド→nupkg化→UiPathにインストール→アクティビティツリーを開くと・・・
　![tree.png](https://qiita-image-store.s3.amazonaws.com/0/255097/8652ab38-69b4-c060-8f18-89ea35548c42.png)
**いた！**

で、Sequenceに置いてみると・・・
　![seq.png](https://qiita-image-store.s3.amazonaws.com/0/255097/e783cacf-a349-4d8e-4198-08a87eb65832.png)
**置けたぁぁぁ！**

いや嬉しい。
最後の【おまけ】に書いた通り、この世界線にたどり着くまでに何度も何度も失敗を重ねたからね。
というわけで、無事に自作アイコンをカスタムアクティビティに設定できました。

---
今回はここまで。
見た目を変えられると、自作アクティビティもいっそう愛着が湧きますね。
次はGet Nowアクティビティの中身の作り込みに入っていきます。

次回＞[[カスタムアクティビティのプロパティを見える化する](https://qiita.com/UmegayaRollcake/items/ca6108560e3b1e183780)]

# 【おまけ】結論だけ、書く。失敗した失敗した失敗した
今回はMS Expression Designで作成したXAML絵をアイコンにしましたが、普通に考えると
「なんで画像ファイルをアイコンにしないの？」って思うよね。

**失敗したからです。** どうやっても画像をアイコンにできなかったので、↓に経緯をまとめました。

まずアイコンにする画像を用意します。
![腕時計アイコン.png](https://qiita-image-store.s3.amazonaws.com/0/255097/b294e34a-6ef1-c2f1-afe5-256761880b91.png)

これをプロジェクトに追加します。その際、"ビルドアクション"プロパティは"埋め込みリソース"に変更。
![res.png](https://qiita-image-store.s3.amazonaws.com/0/255097/9f674629-9b37-4044-e94f-306ae816729e.png)

次にこのPNG画像をデザイナーに組み込みます。
デザイナーのXMLの\<Grid\>タブの上あたりに↓のXMLを追加します。
（UriSourceに画像ファイル名を指定、Sizeはとりあえず32×32）

```
<sap:ActivityDesigner.Icon>
    <DrawingBrush>
        <DrawingBrush.Drawing>
            <ImageDrawing>
                <ImageDrawing.Rect>
                    <Rect Location="0,0" Size="32,32" ></Rect>
                </ImageDrawing.Rect>
                <ImageDrawing.ImageSource>
                    <BitmapImage UriSource="watch.png" />
                </ImageDrawing.ImageSource>
            </ImageDrawing>
        </DrawingBrush.Drawing>
    </DrawingBrush>
</sap:ActivityDesigner.Icon>
```

おおっ、反映された！
![icon.png](https://qiita-image-store.s3.amazonaws.com/0/255097/96b5d7b3-1ee2-5d5b-a85a-25c3409d7c11.png)

テンション上がってきた。

で、このプロジェクトをビルドしてDLLにし、NuGet Package Explorerでnupkgにして
UiPathのManage Packagesでインストールすると、ツリーに念願の自作アイコンが表示・・・
![tree.png](https://qiita-image-store.s3.amazonaws.com/0/255097/e13dd716-3581-88e1-aa13-199b6da6221c.png)

**されない！**というかHDDがずっとカリカリして全然動かん！いつの間にかHDDの**空き容量が0に！**
調べたらUiPathのlogフォルダに大量のCrashreportファイルが発生していた。
![crash.png](https://qiita-image-store.s3.amazonaws.com/0/255097/8804b0ac-78a6-d514-0579-f902efc65903.png)

Crashreportに書かれているエラーの内容は全部同じ。
　Application crashed | [IOException] System.IO.IOException: Cannot locate resource 'watch.png'.
う～ん、プロジェクトに組み込んだはずのPNGファイルが見つからないとな。
デザイナー上では普通に見えていたのに。

Webで調べては色々あがいてみた。

- アクティビティクラスのAttributeに[ToolboxBitmap(typeof(GetNow), "watch.png")]を設定してもダメ
- PNGをResourcesフォルダに入れて[ToolboxBitmap(typeof(GetNow), "Resources.watch.png")]でもダメ
- PNGのビルドアクションを"埋め込みリソース"→"Resource"に変更してもダメ
- 画像をPNGやめてICOファイルにしてもダメ
- 画像のサイズを変えてもダメ
- プロジェクトにリソースファイル(*.resx)を追加してそこにPNGを入れてもダメ
- デザイナーXAMLのBitmapImage UriSourceを"watch.png"<br>→"pack://application:,,,/Umemaru;component/watch.png"に変更してもダメ
- もちろん"pack://application:,,,/watch.png"でもダメ
- デザイナーXAMLのSizeを"16,16"や"64,64"にしてもダメ

といった具合に、何をどうやってもうまくいかず結局あきらめ。
頼みのUiPath Community Forumにもいくつか自作アイコンについての投稿があったけど、成功例は無し。
Webに転がっている成功例はみんな純粋なWWFのケースで、UiPathではなぜかダメみたい。

最後に見つけた[MSDN](https://social.msdn.microsoft.com/Forums/vstudio/en-US/18dd6510-305a-4f59-acb1-f73e8223079b/change-custom-activity-icon?forum=wfprerelease)に、画像じゃなく直接XAML形式でアイコン書く例が紹介されていたので
仕方なくそちらに切り替えてなんとか自作できました。
ドット画像よりもベクターデータのXAMLアイコンの方がUiPath Studioでキレイに表示されるので、
結果的にはXAMLで良かったかな。でも時間返して。