Разбираемся с лентой (Ribbon)
Запись от Fighter размещена 29.01.2012 в 14:23
На просторах Инета достаточно много описаний, как вставить кастомную кнопку на ленту. Вот, например, несколько ссылок:
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 вложенных разделов:
Понятно, что коллекция представляет собой набор элементов с такими же именами, что и имя коллекции, но без окончания ‘s’. Т.е. коллекция <CustomActions> имеет набор элементов <CustomAction>, а коллекция <CommandDefinitions> — набор элементов <CommandDefinition> и т.д. Чтобы различать элементы в коллекции, необходимо задать уникальный идентификатор для каждого элемента. Делается это для всех коллекций одинаково:
Стоит также прислушаться к рекомендациям Microsoft об именовании идентификаторов. Соглашение об именовании MSDN требует использовать следующее правило:
Получится что-то вроде этого:
Общее правило редактирования описания ленты в файле customizations.xml звучит следующим образом: опиши ВСЕ необходимые правила в разделе <RuleDefinitions>, затем в разделе <CommandDefinitions> укажи, КАКИЕ ПРАВИЛА ДЛЯ КАКИХ ЭЛЕМЕНТОВ ленты должны применяться. Чтобы правило в <RuleDefinitions> привязать к команде в <CommandDefinitions>, используется уникальный идентификатор правила.
Таким образом, для каждого элемента на ленте мы можем задать несколько правил видимости / доступности и несколько действий (actions). А чтобы различать эти плавила и действия –используются уникальные идентификаторы (не путать с идентификаторами самих элементов на ленте!).
Что нам нужно для элементов на ленте?
Для каждого элемента коллекции нам нужно будет написать такой код:
где разделы, или группы правил, <EnableRules>, <DisplayRules> будут раскрыты более детально ниже.
Из наименований разделов видно, что они представляют собой коллекции, а значит, содержат элементы с соответствующими названиями. Коллекция <EnableRules> будет содержать элементы <EnableRule> и т.п.
Таким образом, схема нашей работы будет выглядеть следующим образом:
Не допускается ссылки на несуществующее правила. Т.е. если определение правила удалено из <RuleDefinitions>, то все ссылки на него должны быть удалены и из <CommandDefinitions>.
С объявлениями правил и действий все понятно, разберемся с определениями (описаниями).
Группы правил <EnableRule> и <DisplayRule>
Синтаксис описания групп правил идентичен:
<EnableRule>
<DisplayRule>
Полный список правил приведен ниже.
Правило / Раздел <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> можно расширить несколькими опциональными полезными вещами.
Пример:
Для определения состояния элемента на ленте вызывается функция Gl.Quote.ApprovalCommand из библиотеки Gl_Quote_Library пользовательского JavaScript кода.
Возвращаемое функцией булево значение инвертируется (потому что InvertResult="1").
До момента первого вызова функции или при ошибке вызова функции элемент считается разрешенным (потому что Default="true").
Примечание:
<FormStateRule>
Задает состояние элемента в зависимости от состояния формы. Должно быть обязательно указано состояние формы State, при котором элемент на ленте будет разрешен/видим или запрещен/невидим.
Опциональный атрибут Default определяет состояние элемента в случае, когда состояние формы определить не удается (даже не представляю, когда такое может быть).
Опциональный атрибут InvertResult=«1» инвертирует результат применения правила.
Вы можете указать следующие состояния формы, на которые будет реагировать элемент:
Пример:
Элемент на ленте будет разрешен/видим для всех состояний формы, кроме Create (т.е. после того, как новая запись будет сохранена).
<ValueRule>
Задает состояние элемента в зависимости от значения поля на форме. Должны быть обязательно указаны имя поля и отслеживаемое значение.
Правило звучит следующим образом: задать состояние элемента, как только в указанном поле будет установлено указанное значение и запись будет сохранена.
Как и прежде, атрибут InvertResult инвертирует действие правила. Это означает, что если мы хотим, чтобы элемент на ленте был разрешен/видим во всех случаях, кроме случая, когда в поле Field присутствует значение Value, то мы должны использовать InvertResult=«true».
Опциональный атрибут Default определяет состояние элемента в том случае, когда значение поля не определено, т.е. отсутствует (null).
Пример:
Разрешить/показать элемент, когда в наборе параметров PriceCode будет выбрана строка, имеющая значение 2.
Вы можете использовать строковое поле или числовое поле, а не только набор параметров.
Заметьте, что правило сработает не тогда, когда вы введете ключевое значение в отслеживаемое поле (и покинете его), а только после сохранения записи.
<EntityPropertyRule> (применимо только в <DisplayRule>)
Задает видимость или невидимость элемента в зависимости от свойств сущности.
В правиле должны быть обязательно указаны:
Необходимо использовать AppliesTo=”PrimaryEntity” для элементов на главной ленте формы сущности и AppliesTo=”SelectedEntity” для элементов на ленте грида; причем будут проверяться свойства не самой сущности, содержащей грид, а свойства выбранных сущностей в гриде.
Соответственно, применение в правиле опционального атрибута EntityName уместно для случая, когда AppliesTo=”SelectedEntity”, и грид может содержать разные типы сущностей (например, разные Activities).
Как и раньше, опциональные атрибуты Default и InvertResult определяют значение по умолчанию и требование инвертирования результата применения правила.
С помощью правила <EntityPropertyRule> можно контролировать наличие следующих свойств у сущности:
Заметьте, что здесь речь идет не о конкретном экземпляре сущности (записи), а о свойствах сущности как типе объекта. Т.е. проверка свойства HasNotes вернет true для сущности, в которую можно добавлять примечания, независимо от того, есть ли у конкретной записи в настоящий момент примечания или нет.
Пример:
Показать элемент на ленте формы, если сущность может быть связана с Действиями (т.е. Действие может ссылаться на сущность в поле В отношении).
<EntityPrivilegeRule> (применимо только в <DisplayRule>)
Задает видимость или невидимость элемента в зависимости от полномочий пользователя по отношению к заданной сущности.
В правиле должны быть обязательно указаны:
Как и раньше, Default задает состояние элемента по умолчанию, когда невозможно определить обязательные параметры правила (привилегии и уровень доступа), а InvertValue инвертирует значения указанных параметров (привилегии и уровень доступа наоборот).
Опционально можно указать логическое имя сущности, к которой будет применяться это правило, в атрибуте EntityName.
Также можно указать, к какому типу записей данное правило относится: к главной форме или к записям в гриде. В первом случае используем AppliesTo=«PrimaryEntity», во втором — AppliesTo=«SelectedEntity».
Пример:
Показать элемент, если пользователь имеет привилегии на уровне подразделения и имеет право редактировать запись.
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">
X++:
[solution identifier].[entity].[ribbon].[function].[element name]
X++:
<CommandDefinition Id="Gl.Quote.MainGroup.Calculate.Command">
Таким образом, для каждого элемента на ленте мы можем задать несколько правил видимости / доступности и несколько действий (actions). А чтобы различать эти плавила и действия –используются уникальные идентификаторы (не путать с идентификаторами самих элементов на ленте!).
Что нам нужно для элементов на ленте?
- Чтобы они были видимыми или скрытыми в зависимости от нашей логики.
- Чтобы они были видимыми, но либо доступными, либо запрещенными для использования в зависимости, опять же, от нашего желания.
- Чтобы они (при взаимодействии с ними) запускали на выполнение некий пользовательский код.
- <EnableRules> Определяет доступность элементов для взаимодействия
- <DisplayRules> Определяет видимость элементов
- <Actions> Определяет запускаемые сценарии, команды Outlook или открываемые url
Для каждого элемента коллекции нам нужно будет написать такой код:
X++:
<CommandDefinition Id="Gl.Quote.MainGroup.Calculate.Command">
<EnableRules />
<DisplayRules />
<Actions />
</CommandDefinition>
Из наименований разделов видно, что они представляют собой коллекции, а значит, содержат элементы с соответствующими названиями. Коллекция <EnableRules> будет содержать элементы <EnableRule> и т.п.
Таким образом, схема нашей работы будет выглядеть следующим образом:
X++:
<CommandDefinitions> <CommandDefinition> <EnableRules>, <DisplayRules>, <Actions> (.. , ). </CommandDefinitions> <RuleDefinitions> <EnableRules>, <DisplayRules>, <Actions> . </RuleDefinitions>
С объявлениями правил и действий все понятно, разберемся с определениями (описаниями).
Группы правил <EnableRule> и <DisplayRule>
Синтаксис описания групп правил идентичен:
<EnableRule>
X++:
<RuleDefinitions>
<EnableRules >
<EnableRule Id="MyCustomRule">
<CrmClientTypeRule />
<CrmOfflineAccessStateRule />
<ValueRule />
</EnableRule>
</EnableRules>
</RuleDefinitions>
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> можно расширить несколькими опциональными полезными вещами.
- Атрибутом Default. Задает значение по умолчанию. Если функция FunctionName, указанная в правиле, еще не вызвана, то будет использоваться значение Default: true или false.
- Атрибутом InvertResult. Инвертирует значение, возвращаемое функцией FunctionName. Т.е., если FunctionName возвращает true, то элемент на ленте будет запрещен (disable).
Пример:
X++:
<CustomRule Library="$webresource:Gl_Quote_Library" FunctionName="Gl.Quote.ApprovalCommand" Default="true" InvertResult="1"/>
Возвращаемое функцией булево значение инвертируется (потому что InvertResult="1").
До момента первого вызова функции или при ошибке вызова функции элемент считается разрешенным (потому что Default="true").
Примечание:
- Если по каким-либо причинам CRM не сможет вызвать функцию, указанную в <CustomRule>, то для определения состояния кастомного элемента будет использовано значение Default.
- CRM производит успешный вызов функции FunctionName даже если сам ресурс Library не прикреплен к форме (что для меня странно). С целью избегания недоразумений рекомендуется все же указывать в свойствах формы библиотеку с кодом функции, которая должна загружаться вместе с формой.
- Если элемент невидим, то вызов функции FunctionName не производится.
- В функцию FunctionName можно передать параметры, указанные с помощью атрибутов BoolParameter, CrmParameter, DecimalParameter, StringParameter.
<FormStateRule>
Задает состояние элемента в зависимости от состояния формы. Должно быть обязательно указано состояние формы State, при котором элемент на ленте будет разрешен/видим или запрещен/невидим.
Опциональный атрибут Default определяет состояние элемента в случае, когда состояние формы определить не удается (даже не представляю, когда такое может быть).
Опциональный атрибут InvertResult=«1» инвертирует результат применения правила.
Вы можете указать следующие состояния формы, на которые будет реагировать элемент:
- Create Состояние новой записи до ее первого сохранения
- Existing Состояние после сохранения записи, когда пользователь может редактировать данные
- ReadOnly Состояние, когда данные доступны только для чтения
- Disabled Состояние неактивной формы (записи), когда данные нельзя редактировать
- BulkEdit Режим группового редактирования записей
Пример:
X++:
<FormStateRule State="Create" InvertResult="1"/>
<ValueRule>
Задает состояние элемента в зависимости от значения поля на форме. Должны быть обязательно указаны имя поля и отслеживаемое значение.
Правило звучит следующим образом: задать состояние элемента, как только в указанном поле будет установлено указанное значение и запись будет сохранена.
Как и прежде, атрибут InvertResult инвертирует действие правила. Это означает, что если мы хотим, чтобы элемент на ленте был разрешен/видим во всех случаях, кроме случая, когда в поле Field присутствует значение Value, то мы должны использовать InvertResult=«true».
Опциональный атрибут Default определяет состояние элемента в том случае, когда значение поля не определено, т.е. отсутствует (null).
Пример:
X++:
<ValueRule Field="PriceCode" Value="2" Default="true" InvertResult="1"/>
Вы можете использовать строковое поле или числовое поле, а не только набор параметров.
Заметьте, что правило сработает не тогда, когда вы введете ключевое значение в отслеживаемое поле (и покинете его), а только после сохранения записи.
<EntityPropertyRule> (применимо только в <DisplayRule>)
Задает видимость или невидимость элемента в зависимости от свойств сущности.
В правиле должны быть обязательно указаны:
- проверяемое свойство сущности PropertyName.
- какой тип булевого значения PropertyValue должен возвращаться (true или false), если свойство, указанное в PropertyName, имеет место быть.
Необходимо использовать 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"/>
Всего комментариев 2
Комментарии
-
Цитата:CRM производит успешный вызов функции FunctionName даже если сам ресурс Library не прикреплен к форме (что для меня странно).
Спасибо за хороший пост! Буду цитировать вас, если мне будут задавать вопросы по этой теме!
p.s. Вы еще не курили шаблоны рибонов? А то я сломал моск и пока оставил эту попытку.Запись от Артем Enot Грунин размещена 01.02.2012 в 20:08
Обновил(-а) Артем Enot Грунин 01.02.2012 в 20:18 -
Запись от Fighter размещена 05.02.2012 в 02:01