Dynamics CRM 2011 リボンのカスタマイズ パート 2

みなさん、こんにちは。

今回も、前回に引き続きリボンのカスタマイズをお送りします。
SDK にはリボンのカスタマイズサンプルとして、Walkthrough シリーズを
提供しています。その中より、ボタンに関するサンプルを利用して、その
機能を紹介します。

サンプルソリューション

まずは以下のフォルダにあるソリューションを、Dynamics CRM 2011 に
インポートしてください。

sdk\walkthroughs\ribbon\addacustombuttontoanexistinggroupforaspecificentities.zip

結果、取引先企業のグリッドとフォームにカスタムボタンが追加されます。

[取引先企業のグリッド]
image

[取引先企業のフォーム]
image

RibbonDiffXml の構成

前回紹介したとおり、リボンのカスタマイズは、RibbonDiffXml を編集することで
実現しますが、Entities 配下のものと ImportExportXml 配下のものがあります。

また RibbonDiffXml 内には、以下の要素が存在します。

- CustomActions
- Templates
- CommandDefinitions
- RuleDefinitions
- LocLabels

では、サンプルがどうなっているか確認しましょう。

サンプルファイルを開く

1. addacustombuttontoanexistinggroupforaspecificentities.zip ファイルを
展開します。フォルダより customizations.xml を任意の場所へ保存します。

2. Visual Studio 2010 で customizations.xml を開きます。 スキーマとして
customizationssolution.xsd を指定します。スキーマ設定手順が不明な場合には、
前回ブログ記事 のリボンを開くの項目を参照してください。

3. Entity 要素配下に RibbonDiffXml があることを確認します。

LocLabels 要素

まず LocLabels 要素から説明します。

リボンはマルチ言語対応です。タブ、グループ、コントロールの名前や、マウスを
あてたときの説明等を、多言語で表示することが可能です。 LocLabels 要素は
リボン内で利用する文字列を設定することが可能です。

サンプルの LocLabels 要素は以下のようになっています。

<LocLabels>
  <LocLabel Id="Sample.account.SendToOtherSystem.LabelText">
    <Titles>
      <Title languagecode="1033" description="Send to Other System" />
    </Titles>
  </LocLabel>
  <LocLabel Id="Sample.account.SendToOtherSystem.ToolTip">
    <Titles>
      <Title languagecode="1033" description="Sends this Record to another system" />
    </Titles>
  </LocLabel>
</LocLabels>

各 LocLabel 要素に ID 属性が存在します。また Titles 要素内に言語を指定
したラベルを記述するようになっています。対応する言語がない場合には、上記
画像のように、「カスタム」 とだけ表示されますので、今回は以下のように日本語を
足してください。

<LocLabels>
  <LocLabel Id="Sample.account.SendToOtherSystem.LabelText">
    <Titles>
      <Title languagecode="1033" description="Send to Other System" />
      <Title languagecode="1041" description="他システムへ送信" />
    </Titles>
  </LocLabel>
  <LocLabel Id="Sample.account.SendToOtherSystem.ToolTip">
    <Titles>
      <Title languagecode="1033" description="Sends this Record to another system" />
      <Title languagecode="1041" description="他システムへこのレコードを送信" />
    </Titles>
  </LocLabel>
</LocLabels>

RuleDefinitions 要素

RuleDefinitions 要素では、タブ、グループ、コントロールの表示条件が
設定可能です。子要素は以下の 3 つです。

- TabDisplayRules : タブ表示の条件を設定します。
- DisplayRules : グループ、コントロールの表示条件を設定します。
- EnableRules : グループ、コントロールの有効化条件を設定します。

サンプルの RuleDefinitions 要素は以下のように、2 つの DisplayRule
と、3 つの Enable Rule が設定されています。それぞれに ID 属性があります。

<RuleDefinitions>
  <TabDisplayRules />
  <DisplayRules>
    <DisplayRule Id="Sample.account.form.FormStateNotNew.DisplayRule">
      <FormStateRule State="Create" InvertResult="true" />
    </DisplayRule>
    <DisplayRule Id="Sample.account.WebClient.DisplayRule">
      <CrmClientTypeRule Type="Web" />
    </DisplayRule>
  </DisplayRules>
  <EnableRules>
    <EnableRule Id="Sample.account.WebClient.EnableRule">
      <CrmClientTypeRule Type="Web" />
    </EnableRule>
    <EnableRule Id="Sample.account.form.NotNew.EnableRule">
      <FormStateRule State="Create" InvertResult="true" />
    </EnableRule>
    <EnableRule Id="Sample.account.grid.OneSelected.EnableRule">
      <SelectionCountRule AppliesTo="SelectedEntity" Maximum="1" Minimum="1" />
    </EnableRule>
  </EnableRules>
</RuleDefinitions>

DisplayRule の種類

DisplayRule には複数の条件が用意されています。今回のサンプルでは
FormStateRule および CrmClientTypeRule が利用されています。それぞれ
フォームの種類およびクライアントの種類を指定できます。

<FormStateRule State="Create" InvertResult="true" />
InvertResult は結果を逆にして返すという設定なので、この条件場合には、
新規フォームの場合は false、それ以外の更新フォーム等では true を返します。

<CrmClientTypeRule Type="Web" />
この条件では、クライアントの種類が Web、つまり Internet Explorer の場合に
true を返します。

他にも、以下のような条件がありますので、詳細は SDK をご覧ください。
EntiryRule、CrmOutlookClientVersionRule、EntityPrivilegeRule、
EntityPropertyRule 等々

EnableRule の種類

DisplayRule 同様、EnableRule も複数の条件が用意されています。この
サンプルでは以下の 3 つです。

<CrmClientTypeRule Type="Web" />
クライアントの種類が Web の場合 true を返します。

<FormStateRule State="Create" InvertResult="true" />
フォームの種類が新規以外の場合に、true を返します。

<SelectionCountRule AppliesTo="SelectedEntity" Maximum="1" Minimum="1" />
選択されているレコードの数の最大が 1 で最小が 1 の場合、つまりレコードが
1 件だけ選択されている場合に、true を返します。

他にも、以下のような条件がありますので、こちらも SDK を参照してください。
EntityRule、CrmOfflineAccessStateRule、CrmOutlookClientTypeRule、CustomRule
OutlookItemTrackingRule 等々

DisplayRule、EnableRule 共に複数の条件を Or 指定したい場合には、
OrRule が利用できます。

CommandDefinitions 要素

CommandDefinitions 要素は、コントロールがクリックされた場合の動作の指定や、
グループやタブの表示条件を設定できます。CommandDefinition の子要素は
以下の通りです。

- EnableRules : RuleDefinitions で作成した EnableRule を指定します。
- DisplayRules : RuleDefinitions で作成した DisplayRule を指定します。
- Actions: コントロール押下時の動作を指定します。

このサンプルには 2 つ CommandDefinition があります。

<CommandDefinitions>
  <CommandDefinition Id="Sample.account.grid.SendToOtherSystem.Command">
    <EnableRules>
      <EnableRule Id="Sample.account.WebClient.EnableRule" />
      <EnableRule Id="Sample.account.grid.OneSelected.EnableRule" />
    </EnableRules>
    <DisplayRules>
      <DisplayRule Id="Sample.account.WebClient.DisplayRule" />
    </DisplayRules>
    <Actions>
      <JavaScriptFunction Library="$webresource:sample_SendToOtherSystem.js" FunctionName="send" />
    </Actions>
  </CommandDefinition>
  <CommandDefinition Id="Sample.account.form.SendToOtherSystem.Command">
    <EnableRules>
      <EnableRule Id="Sample.account.WebClient.EnableRule" />
      <EnableRule Id="Sample.account.form.NotNew.EnableRule" />
    </EnableRules>
    <DisplayRules>
      <DisplayRule Id="Sample.account.form.FormStateNotNew.DisplayRule" />
      <DisplayRule Id="Sample.account.WebClient.DisplayRule" />
    </DisplayRules>
    <Actions>
      <JavaScriptFunction Library="$webresource:sample_SendToOtherSystem.js" FunctionName="send" />
    </Actions>
  </CommandDefinition>
</CommandDefinitions>

初めの CommandDefinition では、2 つ EnableRule と 1 つDisplayRule を
指定し、さらに 1 つアクションがあります。 EnableRule と DisplayRule には、
既存の RuleDefinitions の ID を指定しています。

Actions 要素では、 JavaScriptFunction 要素を指定しています。つまりこの
CommandDefinition を持つコントロールをクリックすると、ここで指定された
sample_SendToOtherSystem.js スクリプト内の send 関数が実行されます。

JScript は Web リソースとして登録されているため、$webresource: を指定して
アクセスが可能です。

2 つめの CommandDefinition では、 EnableRule、DisplayRule それぞれ
2 つずつ指定してあり、先ほどと同様の Actions が指定されています。

Templates 要素

今回のサンプルでは Templates 要素は指定されていないため、解説は次回
以降で行います。

CustomActions 要素

CustomActions 要素では、2 種類の子要素を指定できます。

- CustomAction : カスタムタブ、グループ、コントロールの追加、また既存の
                              アイテムをリプレースするために使用します。
- HideCustomAction : 既存のタブ、グループ、コントロールを隠すために
                                       使用ります。

このサンプルには 2 つの CustomAction があります。

<CustomActions>
  <CustomAction Id="Sample.account.grid.SendToOtherSystem.CustomAction" Location="Mscrm.HomepageGrid.account.MainTab.Collaborate.Controls._children" Sequence="41">
    <CommandUIDefinition>
      <Button Id="Sample.account.grid.SendToOtherSystem.Button" Command="Sample.account.grid.SendToOtherSystem.Command" LabelText="$LocLabels:Sample.account.SendToOtherSystem.LabelText" ToolTipTitle="$LocLabels:Sample.account.SendToOtherSystem.LabelText" ToolTipDescription="$LocLabels:Sample.account.SendToOtherSystem.ToolTip" TemplateAlias="o1" Image16by16="$webresource:sample_/icons/TIcon16x16.png" Image32by32="$webresource:sample_/icons/TIcon32x32.png" />
    </CommandUIDefinition>
  </CustomAction>
  <CustomAction Id="Sample.account.form.SendToOtherSystem.CustomAction" Location="Mscrm.Form.account.MainTab.Collaborate.Controls._children" Sequence="33">
    <CommandUIDefinition>
      <Button Id="Sample.account.form.SendToOtherSystem.Button" Command="Sample.account.form.SendToOtherSystem.Command" LabelText="$LocLabels:Sample.account.SendToOtherSystem.LabelText" ToolTipTitle="$LocLabels:Sample.account.SendToOtherSystem.LabelText" ToolTipDescription="$LocLabels:Sample.account.SendToOtherSystem.ToolTip" TemplateAlias="o1" Image16by16="$webresource:sample_/icons/TIcon16x16.png" Image32by32="$webresource:sample_/icons/TIcon32x32.png" />
    </CommandUIDefinition>
  </CustomAction>
</CustomActions>

CustomAction 要素

CustomAction には ID 属性と Location 属性があります。 ID は一意の
名称、Location にはカスタムを行う場所を設定します。1 つ目の CustomAction
では、Mscrm.HomepageGrid.account.MainTab.Collaborate.Controls._children が
指定されています。これは取引先企業グリッドのメインタブの共同作業グループに
新しい子要素を加えるという意味です。

既存のロケーション名に関しては、cs\client\ribbon\exportribbonxml 内の
ファイルを参照することで確認が可能です。

もう 1 つには、Mscrm.Form.account.MainTab.Collaborate.Controls._children が
指定されています。これは取引先企業フォームのメインタブの共同作業グループに
新しい子要素を加えるという意味です。

また Sequence 属性では、順序の優先度を指定できます。

CommandUIDefinition 要素とその子要素

CommandUIDefinition 要素自体には指定するものはありません。子要素として
コントロールを指定できます。今回のサンプルでは共に Button コントロールを指定
しています。

Button 要素

Button 要素は、数あるコントロールの 1 つです。多くの属性があり、柔軟な
設定が可能です。以下サンプルの Button 要素の属性です。

Id : 一意の ID を指定。
Command : このコントロールに関連付ける CommandDefinition を ID で指定。
LabelText : このコントロールの表示名を指定。直接文字列を指定することが可能
      だが、多言語対応をして、LocLabels 要素の指定が可能。このサンプルでは、
      "$LocLabels:Sample.account.SendToOtherSystem.LabelText"  を指定
ToolTipTitle: マウスオーバー時のヘルプ表示のタイトル。LabelText と同様に
      LocLabels を指定可能。
ToolTipDescription : マウスオーバー時のヘルプの内容。LocalText と同様に
      LocLabels を指定可能。
TemplateAlias : アイコン表示のテンプレートを指定。詳細は次回記事で説明
Image16by16 と Image32by32 : アイコンの画像。 Web リソースを利用可能

サンプルの更新と動作の確認

日本語のラベルを追加したので、編集した customizations.xml を保存してから、
addacustombuttontoanexistinggroupforaspecificentities.zip 内に上書きし
ソリューションを再度インポートしてください。

表示が以下のように変わっていれば編集成功です。

image

では早速動作の確認を行います。

1. ワークプレース | 取引先企業をクリックして、グリッドを表示します。カスタム
ボタンが表示されていることを確認します。これは以下の定義を満たしている
ためです。

    <DisplayRule Id="Sample.account.WebClient.DisplayRule">
      <CrmClientTypeRule Type="Web" />
    </DisplayRule>

2. レコードが 1 件も選択されていない時点で、カスタムボタンが無効になっている
ことを確認します。これは以下の定義を満たしていないためです。

    <EnableRule Id="Sample.account.grid.OneSelected.EnableRule">
      <SelectionCountRule AppliesTo="SelectedEntity" Maximum="1" Minimum="1" />
    </EnableRule>

3. グリッドよりレコードを 1 件だけ選択して、ボタンが有効になることを
確認します。これは上記ルールを満たしたためです。

4. グリッドよりレコードを複数選択すると、ボタンが無効になることを確認
します。これは上記ルールを満たしていないためです。

5. 既存のレコードを 1 件選択して編集画面を開きます。カスタムボタンが表示され
有効になっていることを確認します。これは以下のルールが満たされているためです。

    <DisplayRule Id="Sample.account.form.FormStateNotNew.DisplayRule">
      <FormStateRule State="Create" InvertResult="true" />
    </DisplayRule>

    <EnableRule Id="Sample.account.form.NotNew.EnableRule">
      <FormStateRule State="Create" InvertResult="true" />
    </EnableRule>

6. レコードを閉じて、グリッド画面より新規ボタンをクリックします。カスタムボタンが
表示されていないことを確認します。これは上記 DisplayRule を満たしていない
ためです。

ルールの編集と動作の確認

では、さらに編集を行ってみましょう。現在の設定では、新規作成フォームには
カスタムボタンが表示さえされませんので、表示だけはされるようにします。

1. customizations.xml を開きます。

2. フォームのカスタムボタンに紐付いている CommandDefinition を編集して
以下のように、DisplayRule の 1 つをコメントアウトします。

<CommandDefinition Id="Sample.account.form.SendToOtherSystem.Command">
  <EnableRules>
    <EnableRule Id="Sample.account.WebClient.EnableRule" />
    <EnableRule Id="Sample.account.form.NotNew.EnableRule" />
  </EnableRules>
  <DisplayRules>
    <!--<DisplayRule Id="Sample.account.form.FormStateNotNew.DisplayRule" />-->
    <DisplayRule Id="Sample.account.WebClient.DisplayRule" />
  </DisplayRules>
  <Actions>
    <JavaScriptFunction Library="$webresource:sample_SendToOtherSystem.js" FunctionName="send" />
  </Actions>
</CommandDefinition>

3. 編集を保存して、addacustombuttontoanexistinggroupforaspecificentities.zip
内に上書きして、再度ソリューションをインポートします。

4. インポート完了後、取引先企業より新規レコード作成フォームを開きます。

5. カスタムボタンが表示され、無効になっていることを確認します。

まとめ

今回のサンプルでは、ボタンコントロールを特定の場所に挿入する
カスタマイズを紹介しました。RibbonDiffXml の構成は一見複雑ですが、
再利用等を考慮した作りになっていますので、慣れればとても便利です。

今回のサンプルをいろいろ編集して、動作の検証をしてみてください。
また類似サンプルとして、全てのエンティティのリボンにコントロールを
追加するサンプルも提供されています。詳細は SDK ウォークスルーの
Walkthrough: Add a Custom Button to an Existing Group for all Entities
を参照してください。

次回以降もより複雑なリボンのカスタマイズを紹介していきますので
お楽しみに!

- Dynamics CRM サポート 中村 憲一郎