AXForum  
Вернуться   AXForum > Блоги > Fighter
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

Оценить эту запись

Разбираемся с лентой (Ribbon)

Запись от Fighter размещена 29.01.2012 в 14:23
Теги crm, ribbon, лента

На просторах Инета достаточно много описаний, как вставить кастомную кнопку на ленту. Вот, например, несколько ссылок:
http://gtcrm.wordpress.com/2011/01/1...-in-crm-2011-3
http://blog.tallan.com/2011/06/24/mi...rom-the-ribbon
http://dynamicscrm2011.wordpress.com...-customization

Ниже речь пойдет о расширенном функционале, позволяющем не только вставить кнопку (или любой другой разрешенный элемент) на ленту, но и «оживить» ее: определив дополнительные правила, когда эта кнопка видна, когда скрыта или когда запрещено нажатие. Детальное описание поведения ленты можно подчерпнуть из библиотеки MSDN, зайдя в раздел Ribbon XML Refference. Описание ниже – для ленивых

Итак, предположим, что определение кастомной кнопки либо другого какого интерфейсного элемента на ленте уже задано в файле customizations.xml.
Все наши правки файла customizations.xml будут затрагивать раздел <RibbonDiffXml> — корневой узел для всех кастомных элементов. Он содержит 5 вложенных разделов:
  • <CustomActions> Содержит коллекцию действий, которые добавляют, изменяют или удаляют элементы на ленте
  • <Templates> Содержит коллекцию шаблонов размещения элементов на ленте
  • <CommandDefinitions> Содержит коллекцию команд и объявлений правил поведения элементов на ленте
  • <RuleDefinitions> Содержит коллекцию определений правил поведения элементов на ленте
  • <LocLabels> Содержит коллекцию локализованных названий элементов ленты

Понятно, что коллекция представляет собой набор элементов с такими же именами, что и имя коллекции, но без окончания ‘s’. Т.е. коллекция <CustomActions> имеет набор элементов <CustomAction>, а коллекция <CommandDefinitions> — набор элементов <CommandDefinition> и т.д. Чтобы различать элементы в коллекции, необходимо задать уникальный идентификатор для каждого элемента. Делается это для всех коллекций одинаково:
X++:
	<CommandDefinition Id="MyFirstCustomElement">
Стоит также прислушаться к рекомендациям Microsoft об именовании идентификаторов. Соглашение об именовании MSDN требует использовать следующее правило:

X++:
[solution identifier].[entity].[ribbon].[function].[element name]
Получится что-то вроде этого:

X++:
	<CommandDefinition Id="Gl.Quote.MainGroup.Calculate.Command">
Общее правило редактирования описания ленты в файле customizations.xml звучит следующим образом: опиши ВСЕ необходимые правила в разделе <RuleDefinitions>, затем в разделе <CommandDefinitions> укажи, КАКИЕ ПРАВИЛА ДЛЯ КАКИХ ЭЛЕМЕНТОВ ленты должны применяться. Чтобы правило в <RuleDefinitions> привязать к команде в <CommandDefinitions>, используется уникальный идентификатор правила.

Таким образом, для каждого элемента на ленте мы можем задать несколько правил видимости / доступности и несколько действий (actions). А чтобы различать эти плавила и действия –используются уникальные идентификаторы (не путать с идентификаторами самих элементов на ленте!).

Что нам нужно для элементов на ленте?
  1. Чтобы они были видимыми или скрытыми в зависимости от нашей логики.
  2. Чтобы они были видимыми, но либо доступными, либо запрещенными для использования в зависимости, опять же, от нашего желания.
  3. Чтобы они (при взаимодействии с ними) запускали на выполнение некий пользовательский код.
За каждое из трех желаний отвечает свой собственный раздел в <CommandDefinitions> и в <RuleDefinitions>:
  • <EnableRules> Определяет доступность элементов для взаимодействия
  • <DisplayRules> Определяет видимость элементов
  • <Actions> Определяет запускаемые сценарии, команды Outlook или открываемые url

Для каждого элемента коллекции нам нужно будет написать такой код:

X++:
	<CommandDefinition Id="Gl.Quote.MainGroup.Calculate.Command">
	   <EnableRules />
	   <DisplayRules />
	   <Actions />
	</CommandDefinition>
где разделы, или группы правил, <EnableRules>, <DisplayRules> будут раскрыты более детально ниже.
Из наименований разделов видно, что они представляют собой коллекции, а значит, содержат элементы с соответствующими названиями. Коллекция <EnableRules> будет содержать элементы <EnableRule> и т.п.
Таким образом, схема нашей работы будет выглядеть следующим образом:
X++:
<CommandDefinitions>
         <CommandDefinition>
         <EnableRules>, <DisplayRules>, <Actions>       (..   ,   ).
</CommandDefinitions>
<RuleDefinitions>
          <EnableRules>, <DisplayRules>, <Actions>
    .
</RuleDefinitions>
Не допускается ссылки на несуществующее правила. Т.е. если определение правила удалено из <RuleDefinitions>, то все ссылки на него должны быть удалены и из <CommandDefinitions>.
С объявлениями правил и действий все понятно, разберемся с определениями (описаниями).

Группы правил <EnableRule> и <DisplayRule>

Синтаксис описания групп правил идентичен:
<EnableRule>
X++:
<RuleDefinitions>
   <EnableRules >
     <EnableRule Id="MyCustomRule">
         <CrmClientTypeRule />
         <CrmOfflineAccessStateRule />
         
         
         <ValueRule />
      </EnableRule>
   </EnableRules>
</RuleDefinitions>
<DisplayRule>
X++:
<RuleDefinitions>
   <DisplayRules>
      <DisplayRule Id="MyCustomRule">
         <CrmClientTypeRule />
         <CrmOfflineAccessStateRule />
         
         
         <ValueRule />
      </DisplayRule>
   </DisplayRules>
</RuleDefinitions>
Полный список правил приведен ниже.

Правило / Раздел <EnableRule> <DisplayRule>
CrmClientTypeRule + +
CrmOfflineAccessStateRule + +
CrmOutlookClientTypeRule + +
CrmOutlookClientVersionRule – +
CustomRule + –
EntityPrivilegeRule – +
EntityPropertyRule – +
EntityRule + +
FormEntityContextRule – +
FormStateRule + +
MiscellaneousPrivilegeRule – +
OrganizationSettingRule – +
OrRule + +
OutlookItemTrackingRule + –
OutlookRenderTypeRule – +
OutlookVersionRule + +
PageRule + +
RecordPrivilegeRule + –
ReferencingAttributeRequiredRule – +
RelationshipTypeRule – +
SelectionCountRule + –
SkuRule + +
ValueRule + +

Детальное описание того, как и какие правила можно определять, содержится в библиотеке MSDN. Рассмотрим только несколько наиболее привлекательных.

<CustomRule> (применимо только в <EnableRule>)

Задает вызов функции JavaScript из библиотеки функций. Должны быть обязательно указаны имя функции и имя библиотеки.
CRM самостоятельно производит вызов функции, указанной в <CustomRule>, в следующих случаях:
  • при открытии формы;
  • при сохранении формы (без закрытия);
  • при возврате на вкладку, где присутствует кастомный элемент, с другой вкладки формы.

Функция должна возвращать булево значение true (1) или false (0), определяющее состояние элемента: элемент разрешен или запрещен.

Описание правила <CustomRule> можно расширить несколькими опциональными полезными вещами.
  1. Атрибутом Default. Задает значение по умолчанию. Если функция FunctionName, указанная в правиле, еще не вызвана, то будет использоваться значение Default: true или false.
  2. Атрибутом InvertResult. Инвертирует значение, возвращаемое функцией FunctionName. Т.е., если FunctionName возвращает true, то элемент на ленте будет запрещен (disable).

Пример:
X++:
<CustomRule Library="$webresource:Gl_Quote_Library" FunctionName="Gl.Quote.ApprovalCommand" Default="true" InvertResult="1"/>
Для определения состояния элемента на ленте вызывается функция Gl.Quote.ApprovalCommand из библиотеки Gl_Quote_Library пользовательского JavaScript кода.
Возвращаемое функцией булево значение инвертируется (потому что InvertResult="1").
До момента первого вызова функции или при ошибке вызова функции элемент считается разрешенным (потому что Default="true").
Примечание:
  1. Если по каким-либо причинам CRM не сможет вызвать функцию, указанную в <CustomRule>, то для определения состояния кастомного элемента будет использовано значение Default.
  2. CRM производит успешный вызов функции FunctionName даже если сам ресурс Library не прикреплен к форме (что для меня странно). С целью избегания недоразумений рекомендуется все же указывать в свойствах формы библиотеку с кодом функции, которая должна загружаться вместе с формой.
  3. Если элемент невидим, то вызов функции FunctionName не производится.
  4. В функцию FunctionName можно передать параметры, указанные с помощью атрибутов BoolParameter, CrmParameter, DecimalParameter, StringParameter.

<FormStateRule>

Задает состояние элемента в зависимости от состояния формы. Должно быть обязательно указано состояние формы State, при котором элемент на ленте будет разрешен/видим или запрещен/невидим.

Опциональный атрибут Default определяет состояние элемента в случае, когда состояние формы определить не удается (даже не представляю, когда такое может быть).
Опциональный атрибут InvertResult=«1» инвертирует результат применения правила.

Вы можете указать следующие состояния формы, на которые будет реагировать элемент:
  • Create Состояние новой записи до ее первого сохранения
  • Existing Состояние после сохранения записи, когда пользователь может редактировать данные
  • ReadOnly Состояние, когда данные доступны только для чтения
  • Disabled Состояние неактивной формы (записи), когда данные нельзя редактировать
  • BulkEdit Режим группового редактирования записей

Пример:
X++:
	<FormStateRule State="Create" InvertResult="1"/>
Элемент на ленте будет разрешен/видим для всех состояний формы, кроме Create (т.е. после того, как новая запись будет сохранена).

<ValueRule>

Задает состояние элемента в зависимости от значения поля на форме. Должны быть обязательно указаны имя поля и отслеживаемое значение.

Правило звучит следующим образом: задать состояние элемента, как только в указанном поле будет установлено указанное значение и запись будет сохранена.

Как и прежде, атрибут InvertResult инвертирует действие правила. Это означает, что если мы хотим, чтобы элемент на ленте был разрешен/видим во всех случаях, кроме случая, когда в поле Field присутствует значение Value, то мы должны использовать InvertResult=«true».
Опциональный атрибут Default определяет состояние элемента в том случае, когда значение поля не определено, т.е. отсутствует (null).

Пример:
X++:
<ValueRule Field="PriceCode" Value="2" Default="true" InvertResult="1"/>
Разрешить/показать элемент, когда в наборе параметров PriceCode будет выбрана строка, имеющая значение 2.
Вы можете использовать строковое поле или числовое поле, а не только набор параметров.
Заметьте, что правило сработает не тогда, когда вы введете ключевое значение в отслеживаемое поле (и покинете его), а только после сохранения записи.

<EntityPropertyRule> (применимо только в <DisplayRule>)

Задает видимость или невидимость элемента в зависимости от свойств сущности.
В правиле должны быть обязательно указаны:
  • проверяемое свойство сущности PropertyName.
  • какой тип булевого значения PropertyValue должен возвращаться (true или false), если свойство, указанное в PropertyName, имеет место быть.
Правило звучит следующим образом: показать (если правило вернет true) или скрыть (если правило вернет false) элемент на ленте, если сущность обладает указанным свойством.

Необходимо использовать AppliesTo=”PrimaryEntity” для элементов на главной ленте формы сущности и AppliesTo=”SelectedEntity” для элементов на ленте грида; причем будут проверяться свойства не самой сущности, содержащей грид, а свойства выбранных сущностей в гриде.

Соответственно, применение в правиле опционального атрибута EntityName уместно для случая, когда AppliesTo=”SelectedEntity”, и грид может содержать разные типы сущностей (например, разные Activities).
Как и раньше, опциональные атрибуты Default и InvertResult определяют значение по умолчанию и требование инвертирования результата применения правила.

С помощью правила <EntityPropertyRule> можно контролировать наличие следующих свойств у сущности:
  • DuplicateDetectionEnabled Для сущности разрешен поиск дубликатов
  • GridFiltersEnabled Разрешена фильтрация в гриде
  • HasStateCode Сущность имеет поле statecode
  • IsConnectionsEnabled Для экземпляров сущности разрешено связывание
  • MailMergeEnabled Сущность поддерживает MailMerge (генерацию документов на основе шаблонов)
  • WorksWithQueue Сущность поддерживает работу с очередью (экземпляр сущности можно включать в очередь)
  • HasActivities К сущности могут быть привязаны Действия (т.е. форма сущности имеет вкладки Действия / Закрытые действия или подобные)
  • IsActivity Сущность определена как Действие
  • HasNotes В сущность можно добавлять примечания
  • IsCustomizable Сущность может настраиваться

Заметьте, что здесь речь идет не о конкретном экземпляре сущности (записи), а о свойствах сущности как типе объекта. Т.е. проверка свойства HasNotes вернет true для сущности, в которую можно добавлять примечания, независимо от того, есть ли у конкретной записи в настоящий момент примечания или нет.

Пример:
X++:
<EntityPropertyRule AppliesTo="PrimaryEntity" PropertyName="HasActivities" PropertyValue="true" Default="true"/>
Показать элемент на ленте формы, если сущность может быть связана с Действиями (т.е. Действие может ссылаться на сущность в поле В отношении).

<EntityPrivilegeRule> (применимо только в <DisplayRule>)

Задает видимость или невидимость элемента в зависимости от полномочий пользователя по отношению к заданной сущности.

В правиле должны быть обязательно указаны:
  • привилегии уровня записи PrivilegeType (т.е. операции, которые разрешены с записью): Create, Read, Write, Delete, Assign, Share, Append, AppendTo (не расшифровываю — и так понятно).
  • уровень доступа к записи PrivilegeDepth: None (нет), Basic (пользователь), Local (подразделение), Deep (головное и все дочерние подразделения), Global (организация).
Правило звучит следующим образом: показать / скрыть элемент на ленте, если пользователь обладает указанными привилегиями и уровнем доступа.

Как и раньше, Default задает состояние элемента по умолчанию, когда невозможно определить обязательные параметры правила (привилегии и уровень доступа), а InvertValue инвертирует значения указанных параметров (привилегии и уровень доступа наоборот).

Опционально можно указать логическое имя сущности, к которой будет применяться это правило, в атрибуте EntityName.

Также можно указать, к какому типу записей данное правило относится: к главной форме или к записям в гриде. В первом случае используем AppliesTo=«PrimaryEntity», во втором — AppliesTo=«SelectedEntity».

Пример:
X++:
<EntityPrivilegeRule PrivilegeDepth="Local" PrivilegeType="Write" Default="true"/>
Показать элемент, если пользователь имеет привилегии на уровне подразделения и имеет право редактировать запись.
Размещено в Без категории
Просмотров 65241 Комментарии 2
Всего комментариев 2

Комментарии

  1. Старый комментарий
    Аватар для Артем Enot Грунин
    Цитата:
    CRM производит успешный вызов функции FunctionName даже если сам ресурс Library не прикреплен к форме (что для меня странно).
    Рибоны и кнопки бывают не только на форме, но и в списках и расширенном поиске. Так что не вижу ничего странного.

    Спасибо за хороший пост! Буду цитировать вас, если мне будут задавать вопросы по этой теме!

    p.s. Вы еще не курили шаблоны рибонов? А то я сломал моск и пока оставил эту попытку.
    Запись от Артем Enot Грунин размещена 01.02.2012 в 20:08 Артем Enot Грунин is offline
    Обновил(-а) Артем Enot Грунин 01.02.2012 в 20:18
  2. Старый комментарий
    Аватар для Fighter
    Доброго время суток, Артем
    Нет, еще не было такой необходимости. Я разбираюсь с темами по мере надобности. Пока до шаблонов не добрался. Но я видел очень подробное описание, кажется, у slivka_83 на его сайте.
    Запись от Fighter размещена 05.02.2012 в 02:01 Fighter is offline
 


Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 21:07.