2012年2月15日水曜日

ActivityDesigner をもたないアクティビティのアイコンを抽出する

以前行ったアクティビティのアイコン抽出ですが、あの方法は関連するアクティビティデザイナーが存在していて利用できる方法です。コードのみで Workflow Foundation を利用しているケースでは特によくあるのが、アクティビティデザイナーを持たないアクティビティが発生する事で、この場合は当然アイコンを抽出する事はできません。

アクティビティデザイナーを利用していない場合では、あまりアイコンを設定する事がないと思われますが、実際にはワークフローデザイナ上で利用する事を考慮しアイコンを設定する事はあります。その場合は次のようにメタデータの登録という形か、クラスに対して属性を設定することで行われます。

   1: Public Sub Register() Implements IRegisterMetadata.Register
   2:     Dim build As New AttributeTableBuilder
   3:  
   4:     build.AddCustomAttributes(GetType(FolderCreateActivity),
   5:                           New ToolboxBitmapAttribute(GetType(FolderCreateActivity), 
   6:                                                      "FolderCreate.png"))
   7:  
   8:     MetadataStore.AddAttributeTable(build.CreateTable)
   9: End Sub

このように設定した場合はアクティビティにアイコンが関連づいているけど、アクティビティデザイナーは存在しない(標準のアクティビティデザイナーが利用される)、という動作になります。

このような場合に、上記で設定したアイコン情報を抽出するには TypeDescriptor クラスを利用します。

   1: 'Activity からアイコンを抽出する
   2: actDes = childAsm.GetTypes().Where(Function(t)
   3:                                        Return GetType(Activity).IsAssignableFrom(t)
   4:                                    End Function)
   5: For Each childAct In actDes
   6:     Dim ch = TypeDescriptor.GetAttributes(childAct).OfType(Of System.Drawing.ToolboxBitmapAttribute)().FirstOrDefault
   7:     If ch Is Nothing Then Continue For
   8:  
   9:     Dim icoRes As DrawingBrush = Nothing
  10:     Dim img = ch.GetImage(childAct)
  11:     If img Is Nothing Then Continue For
  12:     Dim iconImg = TryCast(img, System.Drawing.Bitmap)
  13:     iconImg.MakeTransparent() '透過処理を行う
  14:     'Image から DrawingBrush へ変換
  15:     Dim ms As New MemoryStream
  16:     img.Save(ms, System.Drawing.Imaging.ImageFormat.Png)
  17:     ms.Seek(0, SeekOrigin.Begin)
  18:     Dim bimg As New BitmapImage
  19:     bimg.BeginInit()
  20:     bimg.StreamSource = New MemoryStream(ms.ToArray)
  21:     bimg.EndInit()
  22:     icoRes = New DrawingBrush(New ImageDrawing With {
  23:                               .ImageSource = bimg,
  24:                               .Rect = New Rect(0, 0, img.Size.Width, img.Size.Height)})
  25:     ToolboxIconExtraction.iconsDict.Add(resourceKey, icoRes)
  26: Next

上記のようなロジックにて ToolboxBitmapAttribute として設定されたアイコン情報を抽出することができます。TypeDescriptor.GetAttirbutes メソッドにて対象となるアクティビティから属性情報を抽出、その結果から ToolboxBitMapAttribute 属性の物だけフィルタリングしています。

抽出した ToolboxBitmapAttribute より GetImage メソッドを呼び出すことで設定したアイコン情報が抽出できますが、この抽出結果は Image であり、WPF や WF で利用する Drawing 系とは別のクラスですので、変換を行う必要があります。その方法として、一度 MemoryStream にて保存し、BitmapImage クラスにて取り込ませ、それを基に DrawingBrush を作成するという方法です。注意する点として、途中で MakeTransparent メソッドを呼び出していますが、これを行わないと抽出した画像情報の透過処理が行われず黒い背景な画像となってしまいますので注意してください。

このような形でアイコン情報を抽出すると、アクティビティデザイナーを持たないアクティビティのアイコン情報が利用できるようになります。

IconExtract

ツールボックスにはアイコンが表示されていますが、デザイナ上では表示されていないという特殊な状態になります。この場合のデザイナ側アイコンの変更については、まだ調査中です・・・

0 件のコメント:

コメントを投稿